defshout(word="yes"):return word.capitalize() + "!" scream = shout defdo_something_before(func): print("I do something before then I call the function you gave me") print(func()) do_something_before(scream)# outputs:# I do something before then I call the function you gave me# Yes!
# 一个装饰器是一个需要另一个函数作为参数的函数defmy_shiny_new_decorator(a_function_to_decorate):# 在装饰器内部动态定义一个函数:wrapper(原意:包装纸).# 这个函数将被包装在原始函数的四周# 因此就可以在原始函数之前和之后执行一些代码.defthe_wrapper_around_the_original_function():# 把想要在调用原始函数前运行的代码放这里 print("Before the function runs") # 调用原始函数(需要带括号) a_function_to_decorate() # 把想要在调用原始函数后运行的代码放这里 print("After the function runs") # 直到现在,"a_function_to_decorate"还没有执行过 (HAS NEVER BEEN EXECUTED).# 我们把刚刚创建的 wrapper 函数返回.# wrapper 函数包含了这个函数,还有一些需要提前后之后执行的代码,# 可以直接使用了(It's ready to use!)return the_wrapper_around_the_original_function# Now imagine you create a function you don't want to ever touch again.defa_stand_alone_function(): print("I am a stand alone function, don't you dare modify me") a_stand_alone_function()# outputs: I am a stand alone function, don't you dare modify me # 现在,你可以装饰一下来修改它的行为.# 只要简单的把它传递给装饰器,后者能用任何你想要的代码动态的包装# 而且返回一个可以直接使用的新函数: a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)a_stand_alone_function_decorated()# outputs:# Before the function runs# I am a stand alone function, don't you dare modify me# After the function runs
装饰器的语法糖
我们用装饰器的语法来重写一下前面的例子:
# 一个装饰器是一个需要另一个函数作为参数的函数defmy_shiny_new_decorator(a_function_to_decorate):# 在装饰器内部动态定义一个函数:wrapper(原意:包装纸).# 这个函数将被包装在原始函数的四周# 因此就可以在原始函数之前和之后执行一些代码.defthe_wrapper_around_the_original_function():# 把想要在调用原始函数前运行的代码放这里 print("Before the function runs") # 调用原始函数(需要带括号) a_function_to_decorate() # 把想要在调用原始函数后运行的代码放这里 print("After the function runs") # 直到现在,"a_function_to_decorate"还没有执行过 (HAS NEVER BEEN EXECUTED).# 我们把刚刚创建的 wrapper 函数返回.# wrapper 函数包含了这个函数,还有一些需要提前后之后执行的代码,# 可以直接使用了(It's ready to use!)return the_wrapper_around_the_original_function
@my_shiny_new_decoratordefanother_stand_alone_function(): print("Leave me alone") another_stand_alone_function()# outputs:# Before the function runs# Leave me alone# After the function runs
Python的一个伟大之处在于:方法和函数几乎是一样的(methods and functions are really the same),除了方法的第一个参数应该是当前对象的引用(也就是 self)。这也就意味着只要记住把 self 考虑在内,你就可以用同样的方法给方法创建装饰器:
defmethod_friendly_decorator(method_to_decorate):defwrapper(self, lie): lie = lie - 3# very friendly, decrease age even more :-)return method_to_decorate(self, lie) return wrapper classLucy(object): def__init__(self):self.age = 32 @method_friendly_decoratordefsay_your_age(self, lie): print("I am %s, what did you think?" % (self.age + lie)) l = Lucy()l.say_your_age(-3)# outputs: I am 26, what did you think?
defa_decorator_passing_arbitrary_arguments(function_to_decorate):# The wrapper accepts any argumentsdefa_wrapper_accepting_arbitrary_arguments(*args, **kwargs): print("Do I have args?:") print(args) print(kwargs)# Then you unpack the arguments, here *args, **kwargs# If you are not familiar with unpacking, check:# http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/ function_to_decorate(*args, **kwargs) return a_wrapper_accepting_arbitrary_arguments @a_decorator_passing_arbitrary_argumentsdeffunction_with_no_argument(): print("Python is cool, no argument here.") function_with_no_argument()# outputs# Do I have args?:# ()# {}# Python is cool, no argument here. @a_decorator_passing_arbitrary_argumentsdeffunction_with_arguments(a, b, c): print(a, b, c) function_with_arguments(1, 2, 3)# outputs# Do I have args?:# (1, 2, 3)# {}# 1 2 3 @a_decorator_passing_arbitrary_argumentsdeffunction_with_named_arguments(a, b, c, platypus="Why not ?"): print("Do %s, %s and %s like platypus? %s" % (a, b, c, platypus)) function_with_named_arguments("Bill", "Linus", "Steve", platypus="Indeed!")# outputs# Do I have args ? :# ('Bill', 'Linus', 'Steve')# {'platypus': 'Indeed!'}# Do Bill, Linus and Steve like platypus? Indeed! classMary(object):def__init__(self): self.age = 31 @a_decorator_passing_arbitrary_argumentsdefsay_your_age(self, lie=-3):# You can now add a default value print("I am %s, what did you think ?" % (self.age + lie)) m = Mary()m.say_your_age()# outputs# Do I have args?:# (<__main__.mary object at>,)# {}# I am 28, what did you think?
defdecorator(func):defwrapper(*args, **kwargs):"""doc of wrapper""" print('123')return func(*args, **kwargs) return wrapper @decoratordefsay_hello():"""doc of say hello""" print('同学你好') print(say_hello.__name__)print(say_hello.__doc__)
from functools import wraps defdecorator(func): @wraps(func)defwrapper(*args, **kwargs):"""doc of wrapper""" print('123')return func(*args, **kwargs) return wrapper @decoratordefsay_hello():"""doc of say hello""" print('同学你好') print(say_hello.__name__)print(say_hello.__doc__)
Primer on Python Decoratorshttps://realpython.com/primer-on-python-decorators/#more-real-world-examples
Decorator Basics:Python’s functions are objectshttps://stackoverflow.com/questions/739654/how-to-make-function-decorators-and-chain-them-together#answer-1594484