简介
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
def check_str(func): print('func :',func) def inner(*args,**kwargs): print('args:',args,' ','kwargs: ',kwargs) func(*args,**kwargs) result = func(*args,**kwargs) if result == 'ok': return 'result is %s'%result else: return 'result is failed %s'%result return inner
@check_str def test(data): return data
result = test('no') print(result)
print('~~~~~~~~~~~~~~~~~~~~~~~')
def test2(data): return data
test2 = check_str(test2)
result = test2(data = 'ok') print(result)
|
闭包的理解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def outer(): x = 1 def inner(): print(x) inner()
outer()
def outer(x): def inner(): print(x)
return inner closure = outer(1) closure()
|
更多装饰器 的学习,可以参考,本文下面都是 别人写的内容,总结的非常浅显易懂。
https://www.cnblogs.com/willsdu/p/16422647.html
以下均为参考的内容
现实问题
在实际的项目中,经常会遇到需要在原有项目上加一些功能,但是这些功能可能很快被删除掉,如何实现这种要求呢?下面举例一个简单的函数
1 2
| def foo(): print('hello')
|
如果想打印该函数的执行时间:
1 2 3 4 5 6 7
| from time import time
def foo(): t1 = time() print('hello') t2 = time() print(t2 - t1)
|
这种在原有函数里面加代码,也不符合开闭原则,那么我可以新增加一个函数:
1 2 3 4 5 6 7 8 9
| from time import time
def run_time(func): def wrap(): t1 = time() func() t2 = time() print(t2 - t1) return wrap
|
这么写的确不用修改原来的代码,但是新增函数还是要被调用的。Python参照Java,提供了注解来优化该场景,上述场景可以简写如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from time import time
def run_time(func): def wrap(): t1 = time() func() t2 = time() print(t2 - t1) return wrap
@run_time def foo(): print('hello')
|
修饰函数
Python注解修饰函数时,函数定义的不同,注解的实现也不同
无参数无返回
上面的例子就是无参数无返回值
无参数有返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from time import time
def run_time(func): def wrap(): t1 = time() r = func() t2 = time() print(t2-t1) return r return wrap
@run_time def foo(): return 'hello'
print(foo())
|
有参数无返回
有参数无返回这种情况较少
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from time import time
def run_time(func): def wrap(a, b): t1 = time() func(a, b) t2 = time() print(t2 - t1)
return wrap
@run_time def foo(a, b): print(a + b)
foo(2, 45)
|
有参数有返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from time import time
def run_time(func): def wrap(a, b): t1 = time() r=func(a, b) t2 = time() print(t2 - t1) return r return wrap
@run_time def foo(a, b): return a + b
print(foo(2, 45))
|
装饰器带参数
有时候装饰器可能需要一些参数,这个场景更复杂,具体实现也就是多层套娃来容纳不同的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def namedDecorator(name): def run_time(func): def wrap(a, b): print('this is:{}'.format(name)) r = func(a, b) return r return wrap return run_time
@namedDecorator("装饰器带参数") def foo(a, b): return a + b
print(foo(2, 45))
|
消除副作用
上述的装饰后,foo函数已经不是原来的foo了,已经是被装饰后的函数了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def namedDecorator(name): def run_time(func): def wrap(a, b): '''my decorator''' print('this is:{}'.format(name)) r = func(a, b) return r return wrap return run_time
@namedDecorator("装饰器带参数") def foo(a, b): """example docstring""" return a + b
print(foo(2, 45)) print(foo.__name__, foo.__doc__)
|
返回
1 2 3
| this is:装饰器带参数 47 wrap my decorator
|
使用@wraps装饰器可以消除这种影响
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| from functools import wraps
def namedDecorator(name): def run_time(func): @wraps(func) def wraper(a, b): '''my decorator''' print('this is:{}'.format(name)) r = func(a, b) return r
return wraper
return run_time
@namedDecorator("装饰器带参数") def foo(a, b): """example docstring""" return a + b
print(foo(2, 45)) print(foo.__name__, foo.__doc__)
|
执行结果
1 2 3
| this is:装饰器带参数 47 foo example docstring
|
多个装饰器
如果想要多个装饰器装饰同一个函数会怎样呢?
执行顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from time import time
def run_time_1(func): def wrap(a, b): r = func(a, b) print('run_time_1') return r return wrap
def run_time_2(func): def wrap(a, b): r = func(a, b) print('run_time_2') return r return wrap
@run_time_1 @run_time_2 def foo(a, b): return a + b
print(foo(2, 45))
|
返回结果:
1 2 3
| run_time_2 run_time_1 47
|
结论:离被修饰函数最近的一侧先执行
包裹形式
我们在上面的代码上加几行代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| from time import time
def run_time_1(func): def wrap(a, b): """run_time_1 docstring""" print(func.__name__, func.__doc__) r = func(a, b) print('run_time_1') return r return wrap
def run_time_2(func): def wrap(a, b): """run_time_2 docstring""" r = func(a, b) print('run_time_2') return r return wrap
@run_time_1 @run_time_2 def foo(a, b): """foo docstring""" return a + b
print(foo(2, 45)) print(foo.__name__, foo.__doc__)
|
输出结果:
1 2 3 4 5
| wrap run_time_2 docstring run_time_2 run_time_1 47 wrap run_time_1 docstring
|
结论:这是洋葱一样,一层包一层的结构
当然这可以使用@wrap消除影响,就不加代码了
修饰类
装饰器还可以装饰类,本质不变,都是执行一段自定义代码后再返回,可以用套娃,洋葱打比方
1 2 3 4 5 6 7 8 9 10 11
| def decorator(cls): print("这里可以写被装饰类新增的功能") return cls
@decorator class A(object): def __init__(self): pass
def test(self): print("test")
|
执行结果
与装饰函数不同的是,被装饰的函数需要调用下,被装饰的类,不需要调用,申明阶段即可发挥作用