def shout(word="yes"):
**return** word.capitalize() + "!"
scream = shout
**def** do_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!
# 一个装饰器是一个需要另一个函数作为参数的函数
**def** my_shiny_new_decorator(a_function_to_decorate):
# 在装饰器内部动态定义一个函数:wrapper(原意:包装纸).# 这个函数将被包装在原始函数的四周# 因此就可以在原始函数之前和之后执行一些代码.
**def** the_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.
**def** a_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
装饰器的语法糖
我们用装饰器的语法来重写一下前面的例子:
# 一个装饰器是一个需要另一个函数作为参数的函数
**def** my_shiny_new_decorator(a_function_to_decorate):
# 在装饰器内部动态定义一个函数:wrapper(原意:包装纸).# 这个函数将被包装在原始函数的四周# 因此就可以在原始函数之前和之后执行一些代码.
**def** the_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_decorator
**def** another_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 考虑在内,你就可以用同样的方法给方法创建装饰器:
def method_friendly_decorator(method_to_decorate):
**def** wrapper(self, lie):
lie = lie - 3 # very friendly, decrease age even more :-)
**return** method_to_decorate(self, lie)
**return** wrapper
**class** Lucy(object):
**def** __init__(self):
self.age = 32
@method_friendly_decorator
**def** say_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?
def a_decorator_passing_arbitrary_arguments(function_to_decorate):
# The wrapper accepts any arguments
**def** a_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_arguments
**def** function_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_arguments
**def** function_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_arguments
**def** function_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!
**class** Mary(object):
**def** __init__(self):
self.age = 31
@a_decorator_passing_arbitrary_arguments
**def** say_your_age(self, lie=-3): # You can now add a default valueprint("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 0xb7d303ac>,)# {}# I am 28, what did you think?