Python Decorators
1. 装饰器模式
这个应该来源于装饰器模式,允许向一个现有的对象添加新的功能,同时又不改变其结构,属于结构型模式
这种模式创建一个装饰器类,用来包装原有的类,并在保持类方法签名完整的前提下,提供额外的功能
2. Python中的装饰器函数和装饰器类
装饰器函数
def use_logging(func):
def wrapper():
logging.warn("%s is running" % func.__name__)
return func() # 把 foo 当做参数传递进来时,执行func()就相当于执行foo()
return wrapper
def foo():
print('i am foo')
foo = use_logging(foo) # 因为装饰器 use_logging(foo) 返回的时函数对象 wrapper,这条语句相当于 foo = wrapper
foo() # 执行foo()就相当于执行 wrapper()
Python中的语法糖
def use_logging(func):
def wrapper():
logging.warn("%s is running" % func.__name__)
return func()
return wrapper
@use_logging
def foo():
print("i am foo")
foo()
类装饰器
主要依靠call方法,当使用@形式附加到函数上,就会调用此方法
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')
@Foo
def bar():
print ('bar')
bar()
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、name、参数列表
# 装饰器
def logged(func):
def with_logging(*args, **kwargs):
print func.__name__ # 输出 'with_logging'
print func.__doc__ # 输出 None
return func(*args, **kwargs)
return with_logging
# 函数
@logged
def f(x):
"""does some math"""
return x + x * x
logged(f)
wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器里面的 func 函数中,这使得装饰器里面的 func 函数也有和原函数 foo 一样的元信息了
from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ # 输出 'f'
print func.__doc__ # 输出 'does some math'
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
3. 装饰器顺序
@a @b @c def f (): pass 它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器 f = a(b(c(f)))