什么是装饰器
在不修改原有类或者方法的情况下,给类或者方法添加新的内容。
怎么实现
简单包裹方法
通过得到原有方法的实例,由一个新的方法对其进行包裹,例如:
1 2 3 4 5 6 7 8
| def source_func(): print("这里是原来方法")
def wrapper_func(): print("wrapper方法执行新的内容") source_func();
|
参数包裹方法
由于python可以将方法当作参数进行传递,如果碰到很多需要添加某个功能的函数就可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13
| def wrapper_func(func): print("例如这是一个日志功能,其他的函数都需要新增这样的一段功能") func()
def func1(): print("func1") def func2(): print("func2")
func1 = wrapper_func(func1) func2 = wrapper_func(func2)
|
语法糖
由于在pyhon中这样的需求很多,python语言将这类的包裹方法按照特定语法可以使用 @ 符号的语法糖,具体使用例子如下:
1 2 3 4 5 6 7 8 9 10
| def wrapper_func(func): def wrapper(): print("这里是wrapper方法") return func() return wrapper
@wrapper_func def my_func(): print("这里是自定义方法")
|
额外
带参数的方法如何进行包裹
可以使用 *args、**kwargs
关键字即可
对于单个已知参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| def func1(name): print("i am %s" % name)
def wrapper(name): print("wrapper 方法") return func(name)
def wrapper(*args): print("wrapper方法") return func(*args)
def foo(name, age=None, height=None): print("I am %s, age %s, height %s" % (name, age, height))
def wrapper(*args, **kwargs): logging.warn("%s is running" % func.__name__) return func(*args, **kwargs)
|
带参数的装饰器
装饰器带参数,需要装饰器函数外部在包裹一层。具体如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def use_logging(level): def decorator(func): def wrapper(*args, **kwargs): if level == "warn": logging.warn("%s is running" % func.__name__) elif level == "info": logging.info("%s is running" % func.__name__) return func(*args) return wrapper
return decorator
@use_logging(level="warn") def foo(name='foo'): print("i am %s" % name)
foo()
|
装饰器类
没错,装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__
方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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()
|
Python自带的有用的装饰器
@property
该装饰器可以将类方法变成属性的调用方式。类似于getter setter方法,具体实现如下
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
| class People:
def __init__(self, name, age): self.__name = name self.__age = age
@property def age(self): return self.__age
@age.setter def age(self, age): if isinstance(age, int): self.__age = age else: raise ValueError
@age.deleter def age(self): print("删除年龄数据!")
obj = People("jack", 18) print(obj.age) obj.age = 19 print("obj.age: ", obj.age) del obj.age
--------------------------- 打印结果: 18 obj.age: 19 删除年龄数据!
|