【摘】python和它的装饰器
python和它的装饰器
即使你没听过装饰器,你也一定知道@staticmethod
作为函数的装饰器,你可以这样写
def mydecorator(function):
def wrapped(*args, **kwargs):
# 在调用原始函数之前, 做点什么
result = function(*args, **kwargs)
# 在函数调用之后, 做点什么
# 并返回结果
return result
# 返回warpper作为装饰函数
return wrapped
作为一个例子,我写了个非常随意的
def print_hello(function):
def hello(*args, **kwargs):
print('hello start')
result = function(*args, **kwargs)
print('hello end')
return 'hello %s' % result
return hello
@print_hello
def print_world():
print('world print')
return 'world result'
if __name__ == '__main__':
print(print_world())
它的结果是
hello start
world print
hello end
hello world result
作为类的装饰器,你可以这样写
class DecoratorAsClass(object):
def __init__(self, function):
self.funciton = function
def __call__(self, *args, **kwargs):
# 在调用原始函数之前, 做点什么
result = self.funciton(*args, **kwargs)
# 在调用函数之后, 做点什么
# 并返回结果
return result
作为一个例子,我依旧写了一个很随意的
class PrintWrappedClass(object):
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
print('wrapped start')
result = self.function(*args, **kwargs)
print('wrapped end')
return result
@PrintWrappedClass
class PrintWorld (object):
def print_world(self):
print('world print')
return 'world result'
def print_kitty(self):
print('kitty print')
return 'kitty result'
if __name__ == '__main__':
print(PrintWorld().print_world())
print('___')
print(PrintWorld().print_kitty())
它的结果是
wrapped start
wrapped end
world print
world result
___
wrapped start
wrapped end
kitty print
kitty result
当然,装饰器也可以传参
def repeat(number=3):
def actual_decorator(function):
def wrapper(*args, **kwargs):
result = None
for _ in range(number):
result = function(*args, **kwargs)
return result
return wrapper
return actual_decorator
@repeat(2)
def print_kitty():
print('kitty print')
return 'kitty result'
if __name__ == '__main__':
print(print_kitty())
它的结果是
kitty print
kitty print
kitty result
然后我想了想,为什么不像函数装饰器的模板那么写呢?
于是,我就随意地写了个错误的例子
def error_repeat(function, number=3):
def wrapper(*args, **kwargs):
result = None
for _ in range(number):
result = function(*args, **kwargs)
return result
return wrapper
@error_repeat
def print_world():
print('world print')
return 'world result'
它的结果是
world print
world print
world print
world result
很完美,但是当我想传参数进去的时候,犯难了
呃,就姑且将这个错误的示例当做个笑话看看吧
保存内省的装饰器
from functools import wraps
def preserving_decorator(function):
@wraps(function)
def wrapped(*args, **kwargs):
# 包装函数内部文档
return function(*args, **kwargs)
return wrapped
说实话,我没看懂这段
所以摘录下书中的原话
使用装饰器的常见错误是在使用装饰器时不保存函数元数据(主要是文档字符串和原始函数名)。
前面所有示例都存在这个问题。
装饰器组合创建了一个新函数,并返回一个新对象,但却完全没有考虑原始函数的标识。这将使得调试这样装饰过的函数更加困难,也会破坏可能用到的大多数自动生成文档的工具,因为无法访问原始的文档字符串和函数签名。
摘自 《Python高级编程》