生效原理
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