Python 之 装饰器

装饰器 中的“器”代指函数

所以装饰器本质是函数,用来装饰其它函数。例如:为其它函数添加其他功能

实现装饰器需要的知识:  高阶函数+嵌套函数 == 装饰器

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("\033[32;1mUser has passed authentication\033[0m")
14                     res = func(*args, **kwargs)  # from home
15                     print("---after authenticaion ")
16                     return res
17                 else:
18                     exit("\033[31;1mInvalid username or password\033[0m")
19             elif auth_type == "ldap":
20                 print("搞毛线ldap,不会。。。。")
21 
22         return wrapper
23     return outer_wrapper
24 
25 def index():
26     print("welcome to index page")
27 @auth(auth_type="local") # home = wrapper()
28 def home():
29     print("welcome to home  page")
30     return "from home"
31 
32 @auth(auth_type="ldap")
33 def bbs():
34     print("welcome to bbs  page")
35 
36 index()
37 print(home()) #wrapper()
38 bbs()
采用三层嵌套,第二层用于返回需要被装饰的函数的返回值。
 

猜你喜欢

转载自www.cnblogs.com/WSX1994/p/9104305.html