本质:装饰器就是给 python 函数套上一件外套。作用是在不改变原来的函数下,增强函数功能。
函数装饰器
def log(func):
def wrapper(*args, **kw):
... # 执行一些操作
return func(*args, **kw)
return wrapper
#====================
@log # 等价于 now = log(now)
def now():
print('2019/3/31')
print(now(), now.__name__)
'''
2019/3/31 wrapper
'''
通过上述简单的例子,不难发现装饰器就是给 python 函数套上一件外套。作用是在不改变原来的函数下,增强函数功能。
# 更复杂点的
# 1. 上例中的 now() 通过装饰器后 __name__ 会发生改变,想要保持不变就需要
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
...
return func(*args, **kw)
@log
def now():
pass
print(now.__name__) # 输出是 now 而不再是 wrapper
# 2. 想要在装饰器传参数
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print(text)
...
return func(*args, **kw)
return wrapper
return decorator
@log('hello') # 等价于 now = log('hello')(now)
def now():
pass
# 3. 在 now() 前后分别输出 begin call 和 end call
def log(func):
def wrapper(*args, **kw):
print('begin call')
res = func(*args, **kw)
print('end call')
return res
return wrapper
# 4. 既能 @log 也能 @log('hello')
def log(text):
def decorator(func):
def wrapper(*args, **kw):
return func(*args, **kw)
return wrapper
return decorator if isinstance(text, str) else decorator(text)
@log
def test1():
pass
@log('hello')
def test2():
pass
类装饰器
相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的 __init__
与 __call__
方法。不管调不调用被装饰的函数,都会先调用类装饰器的 __init__()
,调用被装饰的函数后,再调用类装饰器的 __call__()
class Goo(object):
def __init__(self, func):
print('__init__')
self._func = func
def __call__(self, *args, **kw):
print('start call')
self._func(*args, **kw)
print('end call')
@Goo
def test(text):
print('test', text)
test('world')
'''
__init__
start call
test world
end call
'''
网友评论