python,decorator
http://blog.csdn.net/money_bear/article/details/11730729
在stackoverflow上面看到一个关于Python中装饰器问题的回复,瞬间觉得作者简直是神人啊。
原文地址:http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python
这么好的一段东西,实在是忍不住拿过来翻译一下,有删改:
Python's functions are objects
view plaincopyprint?
- def shout(word="yes"):
- return word.capitalize()+"!"
-
- print shout()
- # outputs : 'Yes!'
- # 输出 : 'Yes!'
-
- # As an object, you can assign the function to a variable like any
- # other object
- # 如果函数是个对象,那么它就可以赋值给变量
-
- scream = shout
-
- # Notice we don't use parentheses: we are not calling the function, we are
- # putting the function "shout" into the variable "scream".
- # It means you can then call "shout" from "scream":
- # 注意这里并没有使用括号,也就是说没有调用这个函数
- # 我们只是让变量 "scream" 等于函数 "shout"
- # 意思就是你通过调用 "scream" 函数来调用 "shout" 函数:
-
- print scream()
- # outputs : 'Yes!'
-
- # More than that, it means you can remove the old name 'shout', and
- # the function will still be accessible from 'scream'
- # 另外,这还表示你可以删除老的函数名 'shout'
- # 这个函数依然存在,并且可以通过 'scream' 调用
-
- del shout
- try:
- print shout()
- except NameError, e:
- print e
- #outputs: "name 'shout' is not defined"
-
- print scream()
- # outputs: 'Yes!'
OK, keep that in mind, we are going back to it soon. Another interesting property of Python functions is they can be defined... inside another function!
好了,函数也是一个对象的问题,暂时先讨论到这里。函数还有另外一个很有意思的属性:我们可以在函数里面定义一个函数!
[python] view plaincopyprint?
- def talk():
- # You can define a function on the fly in "talk" ...
- # 你可以在 "talk" 函数运行的时候定义一个函数 ...
- def whisper(word="yes"):
- return word.lower()+"..."
- # ... and use it right away!
- # ... 紧接着调用这个函数!
- print whisper()
- # You call "talk", that defines "whisper" EVERY TIME you call it, then
- # "whisper" is called in "talk".
- # 每调用一次 "talk" 函数,就会定义一个 "whisper" 函数,
- # 然后再调用这个刚刚定义的 "whisper" 函数 .
- talk()
- # outputs:
- # "yes..."
- # But "whisper" DOES NOT EXIST outside "talk":
- # 并且 "whisper" 函数在 "talk" 函数外部是不可见的:
- try:
- print whisper()
- except NameError, e:
- print e
- #outputs : "name 'whisper' is not defined"*
Functions references
view plaincopyprint?
- def getTalk(type="shout"):
-
- # We define functions on the fly
- # 定义一个函数
- def shout(word="yes"):
- return word.capitalize()+"!"
-
- def whisper(word="yes") :
- return word.lower()+"...";
-
- # Then we return one of them
- # 返回其中的而一个函数
- if type == "shout":
- # We don't use "()", we are not calling the function,
- # we are returning the function object
- # 再次注意:这里没有使用"()",我们并没有调用函数,而是将它作为返回值返回出去
- return shout
- else:
- return whisper
-
- # How do you use this strange beast?
- # 刚刚这函数写得那么纠结,到底有什么用呢?
-
- # Get the function and assign it to a variable
- # 调用 getTalk 函数,将返回的函数赋值给一个变量
-
- talk = getTalk()
-
- # You can see that "talk" is here a function object:
- # 现在 "talk" 变成了一个函数对象
- print talk
- #outputs :
-
- # The object is the one returned by the function:
- # 看下调用这个函数会返回什么
- print talk()
- #outputs : Yes!
-
- # And you can even use it directly if you feel wild:
- # 当然您也可以直接调用它:
- print getTalk("whisper")()
- #outputs : yes...
But wait, there is more. If you can return a function, then you can pass one as a parameter:
还有更屌的,你既然可以返回一个函数,当然也可以接受一个函数作为参数
[python] view plaincopyprint?
- 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!
Well, you just have everything needed to understand decorators. You see, decorators are wrappers which means that they let you execute code before and after the function they decorate without the need to modify the function itself.
好了,你已经搞明白了理解装饰器所需的所有基础知识。装饰器(decorator) 就是一个包装机(wrapper),让你能够在不修改原始函数的基础上,在执行函数的前后加入额外的代码
Handcrafted decorators
view plaincopyprint?
- # A decorator is a function that expects ANOTHER function as parameter
- # 装饰器是一个函数,这个函数接收一个函数作为参数
- def my_shiny_new_decorator(a_function_to_decorate):
-
- # Inside, the decorator defines a function on the fly: the wrapper.
- # This function is going to be wrapped around the original function
- # so it can execute code before and after it.
- # 在装饰器(decorator)内部定义了一个函数即前面提到的包装机(wrapper)
- # 这个函数在原始函数的上下添加了一些代码
- # 这些代码在原始函数调用的前后执行.
-
- def the_wrapper_around_the_original_function():
-
- # Put here the code you want to be executed BEFORE the original
- # function is called、
- # 在原始函数前面添加代码,以便在原始函数调用之前执行
- print "Before the function runs"
-
- # Call the function here (using parentheses)
- # 通过装饰器函数的参数调用原始函数
- a_function_to_decorate()
-
- # Put here the code you want to be executed AFTER the original
- # function is called
- # 在原始函数的后面添加代码,以便在原始函数调用之后执行
- print "After the function runs"
-
- # At this point, "a_function_to_decorate" HAS NEVER BEEN EXECUTED.
- # We return the wrapper function we have just created.
- # The wrapper contains the function and the code to execute before
- # and after. It's ready to use!
- # 函数执行到这里,"a_function_to_decorate" 到目前为止还没有执行
- # 我们返回刚刚创建的包装函数(wrapper function)
- # 这个包装函数(wrapper function)包含那些在原始函数执行前后需要被执行的代码
- # 这个返回的包装函数(wrapper function)可以被正常调用
- 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
-
- # Well, you can decorate it to extend its behavior.
- # Just pass it to the decorator, it will wrap it dynamically in
- # any code you want and return you a new function ready to be used:
- # 为了给这个函数添加一些功能,你可以修饰(decorate)它。
- # 只要将这个函数作为参数传递给一个装饰器函数,
- # 那么这个装饰器函数就会动态的为这个待修饰的原始函数前后添加一些代码
- # 并且返回一个新函数给你
-
- 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
Now, you probably want that every time you call a_stand_alone_function, a_stand_alone_function_decorated is called instead. That's easy, just overwrite a_stand_alone_function with the function returned by my_shiny_new_decorator:
你可能觉得每次调用a_stand_alone_function函数的时候,都要用a_stand_alone_function_decorated来代替,这样一点都不优雅。解决这个问题其实很简单,只要把my_shiny_new_decorator函数返回的函数重新赋值给a_stand_alone_function就可以了。
[python] view plaincopyprint?
- 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
- # And guess what? That's EXACTLY what decorators do!
- # 你猜怎么着?Python里面的装饰器就是这么搞的
Decorators demystified
view plaincopyprint?
- @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
Yes, that's all, it's that simple. @decorator is just a shortcut to:
没错!就是那么简单!!@decorator 其实就是下面这段代码的简单写法。
[python] view plaincopyprint?
- another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)
Decorators are just a pythonic variant of the decorator design pattern. There are several classic design patterns embedded in Python to ease development, like iterators.
装饰器其实就是装饰器模式的一种Python形式的方言。在Python里面还内置了一些其他的可以加速开发效率的典型的设计模式,比如说迭代器(iterators)
Of course, you can cumulate decorators:
当然,你也可以同时使用多个装饰器:
[python] view plaincopyprint?
- def bread(func):
- def wrapper():
- print "
- func()
- print "<\______/>"
- return wrapper
- def ingredients(func):
- def wrapper():
- print "#tomatoes#"
- func()
- print "~salad~"
- return wrapper
- def sandwich(food="--ham--"):
- print food
- sandwich()
- #outputs: --ham--
- sandwich = bread(ingredients(sandwich))
- sandwich()
- #outputs:
- #
- # #tomatoes#
- # --ham--
- # ~salad~
- #<\______/>
Using the Python decorator syntax:
使用Python的装饰器语法
[python] view plaincopyprint?
- @bread
- @ingredients
- def sandwich(food="--ham--"):
- print food
- sandwich()
- #outputs:
- #
- # #tomatoes#
- # --ham--
- # ~salad~
- #<\______/>
The order you set the decorators MATTERS:
装饰器的使用顺序也是有影响的
[python] view plaincopyprint?
- @ingredients
- @bread
- def strange_sandwich(food="--ham--"):
- print food
- strange_sandwich()
- #outputs:
- ##tomatoes#
- #
- # --ham--
- #<\______/>
- # ~salad~
Passing arguments to the decorated function