有什么问题或资源分享欢迎大家后台留言或添加微信
关于Python装饰器,考点很多,这里在网上找到一个对Python装饰器解释的很详细的回答。因为是英语的,并且比较长,将通过两篇来进行翻译。原文链接如下:
https://stackoverflow.com/questions/739654/how-to-make-a-chain-of-function-decorators/1594484#1594484
要理解装饰器,你首先必须要知道在Python中,函数是对象。这一点对装饰器有着很重要的影响。让我们用一个简单的例子来看一下为什么:
def shout(word="yes"):
return word.capitalize()+"!"
print(shout())
# 输出 : 'Yes!'
# 因为函数是一个对象,所以你可以像其他任何对象一样,将它赋值给另一个变量
scream = shout
# 注意,在赋值时,我们并没有使用括号(),即表示我们并没有在调用函数
# 我们只是将 "shout" 赋值给了变量 "scream"
# 通过赋值的操作意味着你可以通过调用 scream() 来达到调用 shout()的目的
print(scream())
# 输出 : 'Yes!'
# 更重要的是,你可以移除旧的函数名 "shout"
# 而这个函数仍然可以通过 screac() 来进行调用
del shout
try:
print(shout())
except NameError, e:
print(e)
#输出: "name 'shout' is not defined"
print(scream())
# 输出: 'Yes!'
牢记这一点,我们过会将会回到这一点上。 对Python中的函数而言,另外一个有趣的特点就是在函数体内也可以定义函数。
def talk():
# 你可以在 talk() 中定义一个函数
def whisper(word="yes"):
return word.lower()+"..."
# 并且很快的调用它
print(whisper())
# 你可以调用 "talk",每调用 "talk" 都会定义一次 "whisper"
# 而 "whisper" 在 "talk" 的函数体中被调用
talk()
# 输出:
# "yes..."
# 但是 "whisper" 在 "talk" 外是不存在的
try:
print(whisper())
except NameError, e:
print(e)
#输出 : "name 'whisper' is not defined"*
#Python's functions are objects
好了,你还在坚持看吗?现在到了有趣的部分了… 从上面,你已经知道了,Python中的函数是对象,因此,函数有如下两个特点:
这意味着一个函数可以作为另一个函数的返回值。
def getTalk(kind="shout"):
# 在内部动态定义两个函数
# 这里需要注意的是 on the fly 的翻译,我查了下,在计算机中,可理解为动态生成的。
def shout(word="yes"):
return word.capitalize()+"!"
def whisper(word="yes") :
return word.lower()+"...";
# 然后返回其中一个
if kind == "shout":
# 没有使用 "()",即表示并没有调用函数
# 返回函数对象
return shout
else:
return whisper
# 我们如何使用这个奇怪的特点
# 调用函数并且把它赋值给一个变量
talk = getTalk()
# You can see that "talk" is here a function object:
# 你可以看到,这里的 "talk" 已经是一个函数对象
print(talk)
#输出 : <function shout at 0xb7ea817c>
# The object is the one returned by the function:
# 这个对象是 getTalk() 函数返回的一人对象
print(talk())
#输出 : Yes!
# 简单点,你也可以直接调用进行打印输出
print(getTalk("whisper")())
#输出 : yes...
还有更多别的用法! 如果你可以将函数作为返回值返回,那么函数同样也可以另外一个函数的参数
def doSomethingBefore(func):
print("I do something before then I call the function you gave me")
print(func())
doSomethingBefore(scream)
#outputs:
#I do something before then I call the function you gave me
#Yes!
好了,你现在做好了理解装饰器的准备知识。可以看到装饰器就是 "wrappers",装饰器可以让你在原来函数的代码之前和之前执行代码,并且不会修改原来函数本身。
你会如何手动实现装饰器呢:
# 一个装饰器就是一个函数,它要求另一个函数作为参数
def my_shiny_new_decorator(a_function_to_decorate):
# 在内部,装饰器定义了一个动态的函数:即包装器。
# 这个函数是为了包装原来的函数
# 所以它可以在原来函数之前和之后执行
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" 还没有被执行
# 我们返回了刚创建的包装器函数
# 这个包装器包括了被包装函数以及在它之前和之前要执行的代码。现在它已经准备好被使用了!
return the_wrapper_around_the_original_function
# 现在想象你要创建一个函数,并且你以后永远也不会再调用它了
def a_stand_alone_function():
print("I am a stand alone function, don't you dare modify me")
a_stand_alone_function()
#输出: 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()
#输出:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
现在,你可能希望每次调用a_stand_alone_function时,都会调用a_stand_alone_function_修饰。这很简单,只需用my_shiny_new_decorator返回的函数覆盖a_stand_alone_function:(即你仍然希望使用原来的被包装的函数名来达到调用包装后的函数的目的,可以通过赋值实现)
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#outputs:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
# 这就是装饰器真正做的!
个人英文水平有限,有什么不对的还请指教。
愿关注我们的人都能找到
属于自己的皮球