装饰器 中的“器”代指函数
所以装饰器本质是函数,用来装饰其它函数。例如:为其它函数添加其他功能
实现装饰器需要的知识: 高阶函数+嵌套函数 == 装饰器
1、函数就是“变量”
函数就是“变量”说的就是 函数在内存的存储和回收 和变量类似。
2、高阶函数(函数调用另一个函数,把函数名作为另一个函数的参数)
1 def foo(): 2 print("foo ...") 3 4 def fun(fun): 5 print(fun) 6 fun() # fun = foo 相当于foo 和 fun 所指的内存一样 7 fun(foo) 8 9 #结果 <function foo at 0x0000000003C6E8C8> 10 # foo ...
我们发现 foo.. .执行了 ,是因为foo 和 fun 所指的内存一样 ,函数即变量 可以赋值
但是我们为什么要多此一举,这样执行呢? 来看下面代码:
1 import time 2 def foo(): 3 time.sleep(1) 4 print("foo ...") 5 6 def fun(fun): 7 start_time = time.time() 8 fun() # fun = foo 相当于foo 和 fun 所指的内存一样 9 stop_time = time.time() 10 print("cost time %s" %(stop_time - start_time)) 11 12 foo() 13 fun(foo) 14 15 #结果:foo ... 16 # foo ... 17 # cost time 1.0000572204589844
我们发现我们实现了装饰一个函数 我们执行 foo() 和 fun(foo) 效果不一样 ,fun装饰了 foo 函数
现在 我们已经满足了原则1 :不改变源代码
我们再看另一个函数:
1 import time 2 def bar(): 3 time.sleep(3) 4 print('in the bar') 5 def test2(func): 6 print(func) 7 return func 8 print(test2(bar)) 9 print("------------------") 10 bar=test2(bar) 11 bar() #run bar 12 13 #结果 14 # <function bar at 0x0000000003C6E8C8> 15 # <function bar at 0x0000000003C6E8C8> 16 # ------------------ 17 # <function bar at 0x0000000003C6E8C8> 18 # in the bar
我们满足了两个原则
3、嵌套函数
1 def grandpa(): 2 # x=1 3 def dad(): #只是定义阶段 4 x=2 5 def son(): #只是定义阶段 6 x=3 7 print (x) 8 son() #必须在这个位置执行 9 dad() #必须在这个位置执行 运行dad 10 grandpa()
看下面的例子: 假如我们实际场景有100个函数(这里列举两个),这里的函数已经上线运行,现在需要为每一个函数增加一个日志。如果用下面的方式相当于修改了函数的源代码,万一产生错误那么后果很严重(业务崩溃)。
1 __author__ = "WSX" 2 3 def fun1(): 4 print("fun1") 5 logger("1") 6 def fun2(): 7 print("fun2") 8 logger("2") 9 10 def logger( fun): 11 print("Logger %s" %fun) 12 fun1() 13 fun2()
所以函数一旦写好不要去修改函数源代码。
这里我们就需要装饰器。
装饰器的原则:
1、不会修改被修饰的函数源码
2、不要修改函数的调用方式
现在我们来写一个简单的装饰器:
1 import time 2 def timmer(func): #这是一个装饰器 ,计算时间 3 def warpper(*args,**kwargs): 4 start_time=time.time() 5 func(*args,**kwargs) 6 stop_time=time.time() 7 print('the func run time is %s' %(stop_time-start_time)) 8 return warpper 9 10 @timmer 11 def test1(): 12 time.sleep(3) 13 print('in the test1') 14 test1()
结果:
in the test1 the func run time is 3.0001718997955322
上面的代码满足装饰器的原则。现在来分析程序:
@timmer 相当于test1 = timmer(test1)
现在我们就完成了一个装饰器。timmer是装饰器 test1是需要被装饰的函数
下面是老男孩教育Alex写的复杂的带函数返回值的装饰器(堪称高潮):
1 __author__ = "Alex Li" 2 import time 3 user,passwd = 'alex','abc123' 4 def auth(auth_type): 5 print("auth func:",auth_type) 6 def outer_wrapper(func): 7 def wrapper(*args, **kwargs): 8 print("wrapper func args:", *args, **kwargs) 9 if auth_type == "local": 10 username = input("Username:").strip() 11 password = input("Password:").strip() 12 if user == username and passwd == password: 13 print("