rank vote url
3 1346 1485 2648 url

Python中如何在一个函数中加入多个装饰器?

怎么做才能让一个函数同时用两个装饰器,像下面这样:

  1. @makebold
  2. @makeitalic
  3. def say():
  4. return "Hello"

我希望得到

  1. <b><i>Hello</i></b>

我只是想知道装饰器怎么工作的!


去看看文档,答在下面:

  1. def makebold(fn):
  2. def wrapped():
  3. return "<b>" + fn() + "</b>"
  4. return wrapped
  5. def makeitalic(fn):
  6. def wrapped():
  7. return "<i>" + fn() + "</i>"
  8. return wrapped
  9. @makebold
  10. @makeitalic
  11. def hello():
  12. return "hello world"
  13. print hello() ## returns <b><i>hello world</i></b>

Answer:2

如果你不想看详细的解释的话请看上面那个答案.

装饰器基础

Python的函数都是对象

要了解装饰器,你必须了解Python中的函数都是对象.这个意义非常重要.让我们看看一个简单例子:

  1. def shout(word="yes"):
  2. return word.capitalize()+"!"
  3. print shout()
  4. # 输出 : 'Yes!'
  5. # 作为一个对象,你可以把它赋值给任何变量
  6. scream = shout
  7. # 注意啦我们没有加括号,我们并不是调用这个函数,我们只是把函数"shout"放在了变量"scream"里.
  8. # 也就是说我们可以通过"scream"调用"shout":
  9. print scream()
  10. # 输出 : 'Yes!'
  11. # 你可以删除旧名"shout",而且"scream"依然指向函数
  12. del shout
  13. try:
  14. print shout()
  15. except NameError, e:
  16. print e
  17. #输出: "name 'shout' is not defined"
  18. print scream()
  19. # 输出: 'Yes!'

好了,先记住上面的,一会还会用到.

Python函数另一个有趣的特性就是你可以在一个函数里定义另一个函数!

  1. def talk():
  2. # 你可以在"talk"里定义另一个函数 ...
  3. def whisper(word="yes"):
  4. return word.lower()+"..."
  5. # 让我们用用它!
  6. print whisper()
  7. # 每次调用"talk"时都会定义一次"whisper",然后"talk"会调用"whisper"
  8. talk()
  9. # 输出:
  10. # "yes..."
  11. # 但是在"talk"意外"whisper"是不存在的:
  12. try:
  13. print whisper()
  14. except NameError, e:
  15. print e
  16. #输出 : "name 'whisper' is not defined"*

函数引用

好,终于到了有趣的地方了…

已经知道函数就是对象.因此,对象:

  • 可以赋值给一个变量
  • 可以在其他函数里定义

这就意味着函数可以返回另一个函数.来看看!☺

  1. def getTalk(kind="shout"):
  2. # 在函数里定义一个函数
  3. def shout(word="yes"):
  4. return word.capitalize()+"!"
  5. def whisper(word="yes") :
  6. return word.lower()+"...";
  7. # 返回一个函数
  8. if kind == "shout":
  9. # 这里不用"()",我们不是要调用函数
  10. # 只是返回函数对象
  11. return shout
  12. else:
  13. return whisper
  14. # 怎么用这个特性呢?
  15. # 把函数赋值给变量
  16. talk = getTalk()
  17. # 可以看到"talk"是一个函数对象
  18. print talk
  19. # 输出 : <function shout at 0xb7ea817c>
  20. # 函数返回的是对象:
  21. print talk()
  22. # 输出 : Yes!
  23. # 不嫌麻烦你也可以这么用
  24. print getTalk("whisper")()
  25. # 输出 : yes...

既然可以return一个函数, 你也可以在把函数作为参数传递:

  1. def doSomethingBefore(func):
  2. print "I do something before then I call the function you gave me"
  3. print func()
  4. doSomethingBefore(scream)
  5. # 输出:
  6. #I do something before then I call the function you gave me
  7. #Yes!

学习装饰器的基本知识都在上面了.装饰器就是”wrappers”,它可以让你在你装饰函数之前或之后执行程序,而不用修改函数本身.

自己动手实现装饰器

怎么样自己做呢:

  1. # 装饰器就是把其他函数作为参数的函数
  2. def my_shiny_new_decorator(a_function_to_decorate):
  3. # 在函数里面,装饰器在运行中定义函数: 包装.
  4. # 这个函数将被包装在原始函数的外面,所以可以在原始函数之前和之后执行其他代码..
  5. def the_wrapper_around_the_original_function():
  6. # 把要在原始函数被调用前的代码放在这里
  7. print "Before the function runs"
  8. # 调用原始函数(用括号)
  9. a_function_to_decorate()
  10. # 把要在原始函数调用后的代码放在这里
  11. print "After the function runs"
  12. # 在这里"a_function_to_decorate" 函数永远不会被执行
  13. # 在这里返回刚才包装过的函数
  14. # 在包装函数里包含要在原始函数前后执行的代码.
  15. return the_wrapper_around_the_original_function
  16. # 加入你建了个函数,不想修改了
  17. def a_stand_alone_function():
  18. print "I am a stand alone function, don't you dare modify me"
  19. a_stand_alone_function()
  20. #输出: I am a stand alone function, don't you dare modify me
  21. # 现在,你可以装饰它来增加它的功能
  22. # 把它传递给装饰器,它就会返回一个被包装过的函数.
  23. a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
  24. a_stand_alone_function_decorated()
  25. #输出s:
  26. #Before the function runs
  27. #I am a stand alone function, don't you dare modify me
  28. #After the function runs

现在,你或许每次都想用a_stand_alone_function_decorated代替a_stand_alone_function,很简单,只需要用my_shiny_new_decorator返回的函数重写a_stand_alone_function:

  1. a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
  2. a_stand_alone_function()
  3. #输出:
  4. #Before the function runs
  5. #I am a stand alone function, don't you dare modify me
  6. #After the function runs
  7. # 想到了吗,这就是装饰器干的事!

让我们看看装饰器的真实面纱

用上一个例子,看看装饰器的语法:

  1. @my_shiny_new_decorator
  2. def another_stand_alone_function():
  3. print "Leave me alone"
  4. another_stand_alone_function()
  5. #输出:
  6. #Before the function runs
  7. #Leave me alone
  8. #After the function runs

就这么简单.@decorator就是下面的简写:

  1. another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)

装饰器就是 decorator design pattern的pythonic的变种.在Python中有许多经典的设计模式来满足开发者.

当然,你也可以自己写装饰器:

  1. def bread(func):
  2. def wrapper():
  3. print "</''''''\>"
  4. func()
  5. print "<\______/>"
  6. return wrapper
  7. def ingredients(func):
  8. def wrapper():
  9. print "#tomatoes#"
  10. func()
  11. print "~salad~"
  12. return wrapper
  13. def sandwich(food="--ham--"):
  14. print food
  15. sandwich()
  16. #outputs: --ham--
  17. sandwich = bread(ingredients(sandwich))
  18. sandwich()
  19. #outputs:
  20. #</''''''\>
  21. # #tomatoes#
  22. # --ham--
  23. # ~salad~
  24. #<\______/>

用Python装饰器语法糖:

  1. @bread
  2. @ingredients
  3. def sandwich(food="--ham--"):
  4. print food
  5. sandwich()
  6. #outputs:
  7. #</''''''\>
  8. # #tomatoes#
  9. # --ham--
  10. # ~salad~
  11. #<\______/>

改变一下顺序:

  1. @ingredients
  2. @bread
  3. def strange_sandwich(food="--ham--"):
  4. print food
  5. strange_sandwich()
  6. #outputs:
  7. ##tomatoes#
  8. #</''''''\>
  9. # --ham--
  10. #<\______/>
  11. # ~salad~

现在:回答你的问题…

作为结论,相信你现在已经知道答案了:

  1. # 字体变粗装饰器
  2. def makebold(fn):
  3. # 装饰器将返回新的函数
  4. def wrapper():
  5. # 在之前或者之后插入新的代码
  6. return "<b>" + fn() + "</b>"
  7. return wrapper
  8. # 斜体装饰器
  9. def makeitalic(fn):
  10. # 装饰器将返回新的函数
  11. def wrapper():
  12. # 在之前或者之后插入新的代码
  13. return "<i>" + fn() + "</i>"
  14. return wrapper
  15. @makebold
  16. @makeitalic
  17. def say():
  18. return "hello"
  19. print say()
  20. #输出: <b><i>hello</i></b>
  21. # 这相当于
  22. def say():
  23. return "hello"
  24. say = makebold(makeitalic(say))
  25. print say()
  26. #输出: <b><i>hello</i></b>

别轻松太早,看看下面的高级用法

装饰器高级用法

在装饰器函数里传入参数

  1. # 这不是什么黑魔法,你只需要让包装器传递参数:
  2. def a_decorator_passing_arguments(function_to_decorate):
  3. def a_wrapper_accepting_arguments(arg1, arg2):
  4. print "I got args! Look:", arg1, arg2
  5. function_to_decorate(arg1, arg2)
  6. return a_wrapper_accepting_arguments
  7. # 当你调用装饰器返回的函数时,也就调用了包装器,把参数传入包装器里,
  8. # 它将把参数传递给被装饰的函数里.
  9. @a_decorator_passing_arguments
  10. def print_full_name(first_name, last_name):
  11. print "My name is", first_name, last_name
  12. print_full_name("Peter", "Venkman")
  13. # 输出:
  14. #I got args! Look: Peter Venkman
  15. #My name is Peter Venkman

装饰方法

在Python里方法和函数几乎一样.唯一的区别就是方法的第一个参数是一个当前对象的(self)

也就是说你可以用同样的方式来装饰方法!只要记得把self加进去:

  1. def method_friendly_decorator(method_to_decorate):
  2. def wrapper(self, lie):
  3. lie = lie - 3 # 女性福音 :-)
  4. return method_to_decorate(self, lie)
  5. return wrapper
  6. class Lucy(object):
  7. def __init__(self):
  8. self.age = 32
  9. @method_friendly_decorator
  10. def sayYourAge(self, lie):
  11. print "I am %s, what did you think?" % (self.age + lie)
  12. l = Lucy()
  13. l.sayYourAge(-3)
  14. #输出: I am 26, what did you think?

如果你想造一个更通用的可以同时满足方法和函数的装饰器,用*args,**kwargs就可以了

  1. def a_decorator_passing_arbitrary_arguments(function_to_decorate):
  2. # 包装器接受所有参数
  3. def a_wrapper_accepting_arbitrary_arguments(*args, **kwargs):
  4. print "Do I have args?:"
  5. print args
  6. print kwargs
  7. # 现在把*args,**kwargs解包
  8. # 如果你不明白什么是解包的话,请查阅:
  9. # http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/
  10. function_to_decorate(*args, **kwargs)
  11. return a_wrapper_accepting_arbitrary_arguments
  12. @a_decorator_passing_arbitrary_arguments
  13. def function_with_no_argument():
  14. print "Python is cool, no argument here."
  15. function_with_no_argument()
  16. #输出
  17. #Do I have args?:
  18. #()
  19. #{}
  20. #Python is cool, no argument here.
  21. @a_decorator_passing_arbitrary_arguments
  22. def function_with_arguments(a, b, c):
  23. print a, b, c
  24. function_with_arguments(1,2,3)
  25. #输出
  26. #Do I have args?:
  27. #(1, 2, 3)
  28. #{}
  29. #1 2 3
  30. @a_decorator_passing_arbitrary_arguments
  31. def function_with_named_arguments(a, b, c, platypus="Why not ?"):
  32. print "Do %s, %s and %s like platypus? %s" %\
  33. (a, b, c, platypus)
  34. function_with_named_arguments("Bill", "Linus", "Steve", platypus="Indeed!")
  35. #输出
  36. #Do I have args ? :
  37. #('Bill', 'Linus', 'Steve')
  38. #{'platypus': 'Indeed!'}
  39. #Do Bill, Linus and Steve like platypus? Indeed!
  40. class Mary(object):
  41. def __init__(self):
  42. self.age = 31
  43. @a_decorator_passing_arbitrary_arguments
  44. def sayYourAge(self, lie=-3): # 可以加入一个默认值
  45. print "I am %s, what did you think ?" % (self.age + lie)
  46. m = Mary()
  47. m.sayYourAge()
  48. #输出
  49. # Do I have args?:
  50. #(<__main__.Mary object at 0xb7d303ac>,)
  51. #{}
  52. #I am 28, what did you think?

把参数传递给装饰器

好了,如何把参数传递给装饰器自己?

因为装饰器必须接收一个函数当做参数,所以有点麻烦.好吧,你不可以直接把被装饰函数的参数传递给装饰器.

在我们考虑这个问题时,让我们重新回顾下:

  1. # 装饰器就是一个'平常不过'的函数
  2. def my_decorator(func):
  3. print "I am an ordinary function"
  4. def wrapper():
  5. print "I am function returned by the decorator"
  6. func()
  7. return wrapper
  8. # 因此你可以不用"@"也可以调用他
  9. def lazy_function():
  10. print "zzzzzzzz"
  11. decorated_function = my_decorator(lazy_function)
  12. #输出: I am an ordinary function
  13. # 之所以输出 "I am an ordinary function"是因为你调用了函数,
  14. # 并非什么魔法.
  15. @my_decorator
  16. def lazy_function():
  17. print "zzzzzzzz"
  18. #输出: I am an ordinary function

看见了吗,和”my_decorator“一样只是被调用.所以当你用@my_decorator你只是告诉Python去掉用被变量my_decorator标记的函数.

这非常重要!你的标记能直接指向装饰器.

让我们做点邪恶的事.☺

  1. def decorator_maker():
  2. print "I make decorators! I am executed only once: "+\
  3. "when you make me create a decorator."
  4. def my_decorator(func):
  5. print "I am a decorator! I am executed only when you decorate a function."
  6. def wrapped():
  7. print ("I am the wrapper around the decorated function. "
  8. "I am called when you call the decorated function. "
  9. "As the wrapper, I return the RESULT of the decorated function.")
  10. return func()
  11. print "As the decorator, I return the wrapped function."
  12. return wrapped
  13. print "As a decorator maker, I return a decorator"
  14. return my_decorator
  15. # 让我们建一个装饰器.它只是一个新函数.
  16. new_decorator = decorator_maker()
  17. #输出:
  18. #I make decorators! I am executed only once: when you make me create a decorator.
  19. #As a decorator maker, I return a decorator
  20. # 下面来装饰一个函数
  21. def decorated_function():
  22. print "I am the decorated function."
  23. decorated_function = new_decorator(decorated_function)
  24. #输出:
  25. #I am a decorator! I am executed only when you decorate a function.
  26. #As the decorator, I return the wrapped function
  27. # Let’s call the function:
  28. decorated_function()
  29. #输出:
  30. #I am the wrapper around the decorated function. I am called when you call the decorated function.
  31. #As the wrapper, I return the RESULT of the decorated function.
  32. #I am the decorated function.

一点都不难把.

下面让我们去掉所有可恶的中间变量:

  1. def decorated_function():
  2. print "I am the decorated function."
  3. decorated_function = decorator_maker()(decorated_function)
  4. #输出:
  5. #I make decorators! I am executed only once: when you make me create a decorator.
  6. #As a decorator maker, I return a decorator
  7. #I am a decorator! I am executed only when you decorate a function.
  8. #As the decorator, I return the wrapped function.
  9. # 最后:
  10. decorated_function()
  11. #输出:
  12. #I am the wrapper around the decorated function. I am called when you call the decorated function.
  13. #As the wrapper, I return the RESULT of the decorated function.
  14. #I am the decorated function.

让我们简化一下:

  1. @decorator_maker()
  2. def decorated_function():
  3. print "I am the decorated function."
  4. #输出:
  5. #I make decorators! I am executed only once: when you make me create a decorator.
  6. #As a decorator maker, I return a decorator
  7. #I am a decorator! I am executed only when you decorate a function.
  8. #As the decorator, I return the wrapped function.
  9. #最终:
  10. decorated_function()
  11. #输出:
  12. #I am the wrapper around the decorated function. I am called when you call the decorated function.
  13. #As the wrapper, I return the RESULT of the decorated function.
  14. #I am the decorated function.

看到了吗?我们用一个函数调用”@“语法!:-)

所以让我们回到装饰器的.如果我们在函数运行过程中动态生成装饰器,我们是不是可以把参数传递给函数?

  1. def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
  2. print "I make decorators! And I accept arguments:", decorator_arg1, decorator_arg2
  3. def my_decorator(func):
  4. # 这里传递参数的能力是借鉴了 closures.
  5. # 如果对closures感到困惑可以看看下面这个:
  6. # http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python
  7. print "I am the decorator. Somehow you passed me arguments:", decorator_arg1, decorator_arg2
  8. # 不要忘了装饰器参数和函数参数!
  9. def wrapped(function_arg1, function_arg2) :
  10. print ("I am the wrapper around the decorated function.\n"
  11. "I can access all the variables\n"
  12. "\t- from the decorator: {0} {1}\n"
  13. "\t- from the function call: {2} {3}\n"
  14. "Then I can pass them to the decorated function"
  15. .format(decorator_arg1, decorator_arg2,
  16. function_arg1, function_arg2))
  17. return func(function_arg1, function_arg2)
  18. return wrapped
  19. return my_decorator
  20. @decorator_maker_with_arguments("Leonard", "Sheldon")
  21. def decorated_function_with_arguments(function_arg1, function_arg2):
  22. print ("I am the decorated function and only knows about my arguments: {0}"
  23. " {1}".format(function_arg1, function_arg2))
  24. decorated_function_with_arguments("Rajesh", "Howard")
  25. #输出:
  26. #I make decorators! And I accept arguments: Leonard Sheldon
  27. #I am the decorator. Somehow you passed me arguments: Leonard Sheldon
  28. #I am the wrapper around the decorated function.
  29. #I can access all the variables
  30. # - from the decorator: Leonard Sheldon
  31. # - from the function call: Rajesh Howard
  32. #Then I can pass them to the decorated function
  33. #I am the decorated function and only knows about my arguments: Rajesh Howard

好了,上面就是带参数的装饰器.参数可以设置成变量:

  1. c1 = "Penny"
  2. c2 = "Leslie"
  3. @decorator_maker_with_arguments("Leonard", c1)
  4. def decorated_function_with_arguments(function_arg1, function_arg2):
  5. print ("I am the decorated function and only knows about my arguments:"
  6. " {0} {1}".format(function_arg1, function_arg2))
  7. decorated_function_with_arguments(c2, "Howard")
  8. #输出:
  9. #I make decorators! And I accept arguments: Leonard Penny
  10. #I am the decorator. Somehow you passed me arguments: Leonard Penny
  11. #I am the wrapper around the decorated function.
  12. #I can access all the variables
  13. # - from the decorator: Leonard Penny
  14. # - from the function call: Leslie Howard
  15. #Then I can pass them to the decorated function
  16. #I am the decorated function and only knows about my arguments: Leslie Howard

你可以用这个小技巧把任何函数的参数传递给装饰器.如果你愿意还可以用*args,**kwargs.但是一定要记住了装饰器只能被调用一次.当Python载入脚本后,你不可以动态的设置参数了.当你运行import x,函数已经被装饰,所以你什么都不能动了.

来练习一下:装饰装饰器

好吧,作为奖励,我就给你讲讲如何怎么让所有的装饰器接收任何参数.为了接收参数,我们用另外的函数来建我们的装饰器.

我们包装装饰器.

还有什么我们可以看到吗?

对了,装饰器!

让我们来为装饰器一个装饰器:

  1. def decorator_with_args(decorator_to_enhance):
  2. """
  3. 这个函数将被用来作为装饰器.
  4. 它必须去装饰要成为装饰器的函数.
  5. 休息一下.
  6. 它将允许所有的装饰器可以接收任意数量的参数,所以以后你不必为每次都要做这个头疼了.
  7. saving you the headache to remember how to do that every time.
  8. """
  9. # 我们用传递参数的同样技巧.
  10. def decorator_maker(*args, **kwargs):
  11. # 我们动态的建立一个只接收一个函数的装饰器,
  12. # 但是他能接收来自maker的参数
  13. def decorator_wrapper(func):
  14. # 最后我们返回原始的装饰器,毕竟它只是'平常'的函数
  15. # 唯一的陷阱:装饰器必须有这个特殊的,否则将不会奏效.
  16. return decorator_to_enhance(func, *args, **kwargs)
  17. return decorator_wrapper

下面是如何用它们:

  1. # 下面的函数是你建来当装饰器用的,然后把装饰器加到上面:-)
  2. # 不要忘了这个 "decorator(func, *args, **kwargs)"
  3. @decorator_with_args
  4. def decorated_decorator(func, *args, **kwargs):
  5. def wrapper(function_arg1, function_arg2):
  6. print "Decorated with", args, kwargs
  7. return func(function_arg1, function_arg2)
  8. return wrapper
  9. # 现在你用你自己的装饰装饰器来装饰你的函数(汗~~~)
  10. @decorated_decorator(42, 404, 1024)
  11. def decorated_function(function_arg1, function_arg2):
  12. print "Hello", function_arg1, function_arg2
  13. decorated_function("Universe and", "everything")
  14. #输出:
  15. #Decorated with (42, 404, 1024) {}
  16. #Hello Universe and everything
  17. # Whoooot!

估计你看到这和你刚看完爱因斯坦相对论差不多,但是现在如果明白怎么用就好多了吧.

最好的练习:装饰器

  • 装饰器是Python2.4里引进的,所以确保你的Python解析器的版本>=2.4
  • 装饰器使函数调用变慢了.一定要记住.
  • 装饰器不能被取消(有些人把装饰器做成可以移除的但是没有人会用)所以一旦一个函数被装饰了.所有的代码都会被装饰.
  • 用装饰器装饰函数将会很难debug(在>=2.5版本将会有所改善;看下面)

functools模块在2.5被引进.它包含了一个functools.wraps()函数,可以复制装饰器函数的名字,模块和文档给它的包装器.

(事实上:functools.wraps()是一个装饰器!☺)

  1. #为了debug,堆栈跟踪将会返回函数的 __name__
  2. def foo():
  3. print "foo"
  4. print foo.__name__
  5. #输出: foo
  6. # 如果加上装饰器,将变得有点复杂
  7. def bar(func):
  8. def wrapper():
  9. print "bar"
  10. return func()
  11. return wrapper
  12. @bar
  13. def foo():
  14. print "foo"
  15. print foo.__name__
  16. #输出: wrapper
  17. # "functools" 将有所帮助
  18. import functools
  19. def bar(func):
  20. # 我们所说的"wrapper",正在包装 "func",
  21. # 好戏开始了
  22. @functools.wraps(func)
  23. def wrapper():
  24. print "bar"
  25. return func()
  26. return wrapper
  27. @bar
  28. def foo():
  29. print "foo"
  30. print foo.__name__
  31. #输出: foo

怎么使用装饰器?

现在遇到了大问题:我们用装饰器干什么?

看起来很黄很暴力,但是如果有实际用途就更好了.好了这里有1000个用途.传统的用法就是用它来为外部的库的函数(你不能修改的)做扩展,或者debug(你不想修改它,因为它是暂时的).

你也可以用DRY的方法去扩展一些函数,像:

  1. def benchmark(func):
  2. """
  3. A decorator that prints the time a function takes
  4. to execute.
  5. """
  6. import time
  7. def wrapper(*args, **kwargs):
  8. t = time.clock()
  9. res = func(*args, **kwargs)
  10. print func.__name__, time.clock()-t
  11. return res
  12. return wrapper
  13. def logging(func):
  14. """
  15. A decorator that logs the activity of the script.
  16. (it actually just prints it, but it could be logging!)
  17. """
  18. def wrapper(*args, **kwargs):
  19. res = func(*args, **kwargs)
  20. print func.__name__, args, kwargs
  21. return res
  22. return wrapper
  23. def counter(func):
  24. """
  25. A decorator that counts and prints the number of times a function has been executed
  26. """
  27. def wrapper(*args, **kwargs):
  28. wrapper.count = wrapper.count + 1
  29. res = func(*args, **kwargs)
  30. print "{0} has been used: {1}x".format(func.__name__, wrapper.count)
  31. return res
  32. wrapper.count = 0
  33. return wrapper
  34. @counter
  35. @benchmark
  36. @logging
  37. def reverse_string(string):
  38. return str(reversed(string))
  39. print reverse_string("Able was I ere I saw Elba")
  40. print reverse_string("A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!")
  41. #输出:
  42. #reverse_string ('Able was I ere I saw Elba',) {}
  43. #wrapper 0.0
  44. #wrapper has been used: 1x
  45. #ablE was I ere I saw elbA
  46. #reverse_string ('A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!',) {}
  47. #wrapper 0.0
  48. #wrapper has been used: 2x
  49. #!amanaP :lanac a ,noep a ,stah eros ,raj a ,hsac ,oloR a ,tur a ,mapS ,snip ,eperc a ,)lemac a ro( niaga gab ananab a ,gat a ,nat a ,gab ananab a ,gag a ,inoracam ,elacrep ,epins ,spam ,arutaroloc a ,shajar ,soreh ,atsap ,eonac a ,nalp a ,nam A

当然,装饰器的好处就是你可以用它们来做任何事而不用重写,DRY:

  1. @counter
  2. @benchmark
  3. @logging
  4. def get_random_futurama_quote():
  5. from urllib import urlopen
  6. result = urlopen("http://subfusion.net/cgi-bin/quote.pl?quote=futurama").read()
  7. try:
  8. value = result.split("<br><b><hr><br>")[1].split("<br><br><hr>")[0]
  9. return value.strip()
  10. except:
  11. return "No, I'm ... doesn't!"
  12. print get_random_futurama_quote()
  13. print get_random_futurama_quote()
  14. #输出:
  15. #get_random_futurama_quote () {}
  16. #wrapper 0.02
  17. #wrapper has been used: 1x
  18. #The laws of science be a harsh mistress.
  19. #get_random_futurama_quote () {}
  20. #wrapper 0.01
  21. #wrapper has been used: 2x
  22. #Curse you, merciful Poseidon!

Python自身提供了几个装饰器,像property, staticmethod.

  • Django用装饰器管理缓存和试图的权限.
  • Twisted用来修改异步函数的调用.

好大的坑!