python 装饰器

mac2022-06-30  21

生效原理

1、@ 装饰器语法 装饰器实际是一个函数,或实现了‘call()’函数,可以像函数一样使用"()"直接调用的类。 装饰器语法的含义:以被装饰的函数为参数,调用装饰器函数。代码解释如下:

def a_new_decorator(a_func): print 'excute in a_new_decorator' return 'str_return_in_a_new_decorator' @a_new_decorator def a_function_need_decoration(): print 'in a_function_need_decoration' ## @a_new_decorator 声明后,会执行 a_function_need_decoration = a_new_decorator(a_function_need_decoration), ## 本质上是以被装饰函数名作为变量,重新赋值为装饰器函数的返回值 print 'a_function_need_decoration == %s' % a_function_need_decoration

输出: excute in a_new_decorator a_function_need_decoration == str_return_in_a_new_decorator

上述第一行输出是装饰器函数中 print 语句打印,@a_new_decorator声明时,装饰器函数就会被调用。第二行证明函数名作为变量被重新赋值为装饰器函数的返回值。本例中,装饰器函数返回了一个字符串,因此a_function_need_decoration变为一个字符串变量,变量值是‘str_return_in_a_new_decorator’。

2、用装饰器包装函数 装饰器一般用来“包裹”被装饰函数,示例如下。可以看到调用 a_function_requiring_decoration 函数时,实际调用的是装饰器返回函数wrapTheFunctn,a_function_requiring_decoration的调用语句被“包裹”在wrapTheFunctn 函数中。这样可以在不改动a_function_requiring_decoration代码情况下,为其增加新的功能(即在执行被装饰函数前后,执行一些其他的代码)。

def a_new_decorator(a_func): def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction @a_new_decorator def a_function_requiring_decoration(): """Hey you! Decorate me!""" print("I am the function which needs some decoration to " "remove my foul smell") a_function_requiring_decoration() #outputs: I am doing some boring work before executing a_func() # I am the function which needs some decoration to remove my foul smell # I am doing some boring work after executing a_func() #the @a_new_decorator is just a short way of saying: a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

如果我们运行如下代码会存在一个问题:

print(a_function_requiring_decoration.__name__) # Output: wrapTheFunction

这并不是我们想要的!Ouput输出应该是"a_function_requiring_decoration"。这里的函数被warpTheFunction替代了。它重写了我们函数的名字和注释文档(docstring)。幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps。我们修改上一个例子来使用functools.wraps:

from functools import wraps def a_new_decorator(a_func): @wraps(a_func) def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction @a_new_decorator def a_function_requiring_decoration(): """Hey yo! Decorate me!""" print("I am the function which needs some decoration to " "remove my foul smell") print(a_function_requiring_decoration.__name__) # Output: a_function_requiring_decoration

3、带参数的装饰器 示例:@test_outest_func(‘test para’) ,实际上不是装饰器带参数,这里有两个运算符,一个是函数调用运算符(),另一个是@。"()“优先级高于”@",因此先执行函数调用 test_outest_func(‘test para’),test_outest_func(‘test para’)的返回值是一个装饰器函数。

from functools import wraps def test_outest_func(str): def a_new_decorator(a_func): @wraps(a_func) def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction return a_new_decorator @test_outest_func('test para') def a_function_requiring_decoration(): """Hey you! Decorate me!""" print("I am the function which needs some decoration to " "remove my foul smell")

应用场景

装饰器有很多应用场景,可以让代码管理更简单。部分场景举例如下。 1、授权 执行函数 ‘f’ 之前,先检查是否有权限

from functools import wraps def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): auth = request.authorization if not auth or not check_auth(auth.username, auth.password): authenticate() return f(*args, **kwargs) return decorated

2、日志

from functools import wraps def logit(func): @wraps(func) def with_logging(*args, **kwargs): print(func.__name__ + " was called") return func(*args, **kwargs) return with_logging @logit def addition_func(x): """Do some math.""" return x + x result = addition_func(4) # Output: addition_func was called

装饰器类

实现"call"函数, “call” 即装饰器函数。这里为什么不用先实例化logit类,还有待研究。

from functools import wraps class logit(object): def __init__(self, logfile='out.log'): self.logfile = logfile def __call__(self, func): # 实现 __call__ 函数 @wraps(func) def wrapped_function(*args, **kwargs): log_string = func.__name__ + " was called" print(log_string) # 打开logfile并写入 with open(self.logfile, 'a') as opened_file: # 现在将日志打到指定的文件 opened_file.write(log_string + '\n') # 现在,发送一个通知 self.notify() return func(*args, **kwargs) return wrapped_function def notify(self): # logit只打日志,不做别的 pass @logit() def myfunc1(): pass

类的装饰器

类的装饰器,和函数的装饰器语义一致。下面代码中,@six.add_metaclass(Meta)语义是 MyClass = six.add_metaclass(Meta)(MyClass),即先调用函数six.add_metaclass(Meta),再six.add_metaclass(Meta)(MyClass)。

import six @six.add_metaclass(Meta) class MyClass(object): pass

参考:https://www.runoob.com/w3cnote/python-func-decorators.html

最新回复(0)