装饰器的作用与原理相当于java中的注解 我们可以在不入侵一个函数的情况下,在这个函数前和函数后,执行一些预设的功能。通常我们会把函数中都会用到的某一类功能(如:鉴权、日志、参数校验等)封装成一个装饰器,这样代码更简洁,语义也更清晰。 在python中用@ 装饰器函数,简化了上述设计模式的使用过程 我们来看一个简单应用 def log(fn): def wrap_function(): print('准备运行函数fn') fn() print('函数fn运行结束') return wrap_function@logdef fnA(): print('正在运行fnA....')fnA()# 输出:'''准备运行函数fn正在运行fnA....函数fn运行结束''' 与下面的代码是等价的
使用扩展
def log(fn): def wrap_function(a): print('原函数入参...', a) print('准备运行函数fn') fn(a) print('函数fn运行结束') return wrap_function @log def fnA(a): print('正在运行fnA...', a) fnA('入参A') # 输出: ''' 原函数入参... 入参A 准备运行函数fn 正在运行fnA... 入参A 函数fn运行结束 '''
函数装饰器嵌套执行顺序先由上到下执行before,执行完原函数后,再由下往上执行After函数 def deA(fn): def wrap_function(*args, **kwargs): print('deA原函数入参...', args) print('deA准备运行函数fn') fn(*args, **kwargs) print('deA函数fn运行结束') return wrap_functiondef deB(fn): def wrap_function(*args, **kwargs): print('deB原函数入参...', args) print('deB准备运行函数fn') fn(*args, **kwargs) print('deB函数fn运行结束') return wrap_functiondef deC(fn): def wrap_function(*args, **kwargs): print('deC原函数入参...', args) print('deC准备运行函数fn') fn(*args, **kwargs) print('deC函数fn运行结束') return wrap_function@deA@deB@deCdef fnA(a, b): print('正在运行fnA...', a, b)fnA('入参A', '入参B')# 输出:'''deA原函数入参... ('入参A', '入参B')deA准备运行函数fndeB原函数入参... ('入参A', '入参B')deB准备运行函数fndeC原函数入参... ('入参A', '入参B')deC准备运行函数fn正在运行fnA... 入参A 入参BdeC函数fn运行结束deB函数fn运行结束deA函数fn运行结束''' 带参数的装饰器在上述基本的装饰器的基础上,在外面套一层接收参数的函数,来实现装饰器带参数功能
Python常用的内置装饰器@staticmethod、 @classmethod、 @property、@abstractmethod
class B: @staticmethod def add(a, b): return a + b B.add(10, 5) # 15
class B: def __init__(self): self._var1 = 3 self.var2 = 5 @property def var1(self): return self._var1b = B() b.var1 b.var1 = 10 # 尝试给其赋值,会报错
@wraps()语法糖由于Python的装饰器是通过闭包实现的,所以在装饰函数中,获取导的属性并非原函数,这就不是很完美 def logger(fn): def wrap_function(*args, **kwargs): ''' 这是装饰器函数 ''' print('装饰器中。。。。') return fn(*args, **kwargs) return wrap_function@loggerdef fnA(): ''' fnA中的打印 ''' print('正在运行fnA....')print(fnA.__name__, fnA.__doc__)# 输出:'''wrap_function 这是装饰器函数''' 加上@wraps() 后,修饰内部函数,保证这个内部函数带有传进来这个函数的属性
类装饰器通过 __call__ 将类变成调用对象 class Logger: def __init__(self, func): self.func = func def print_console(self): print('console print') def __call__(self, *args, **kwargs): self.print_console() self.func()@Loggerdef fnA(): print('fnA正在运行。。。')fnA()# 输出'''console printfnA正在运行。。。''' 带参数的类装饰器
有了类装饰器,就可以使用继承了 from functools import wrapsclass Logger: def __init__(self, prefix='logger'): self.prefix = prefix def print_console(self): print('console print', self.prefix) def notify(self): self.print_console() def __call__(self, func): @wraps(func) def wrapper(*args, **kwargs): print(self.prefix, 'wrapper before...') self.notify() ret = func(*args, **kwargs) print(self.prefix, 'wrapper after...') return ret return wrapperclass EmailLogger(Logger): def __init__(self, prefix='Email', email='abc@test.com'): Logger.__init__(self, prefix) self.email = email def print_email(self): print('email print:', self.email) def notify(self): self.print_email()@EmailLogger(email='test@test.com')def fnA(): print('fnA正在运行。。。')fnA()# 输出:'''Email wrapper before...email print: test@test.comfnA正在运行。。。Email wrapper after...''' |
|