我们时常看到这样的python写法——Python函数定义前面加了一坨@XXX。
@my_decorator
def my_func():
print "I am a stand-alone function"
它的功能是:在不改动my_func()的前提下,实现以my_func为核心的功能扩展。
例如,在某种扩展方式下,my_func()的执行结果是:func()的输出上下各增加一行:
>> my_func()
# output
Before the function runs
I am a stand-alone function
After the function runs
上述某种扩展是在哪里定义的呢——在函数my_decorator里,其定义如下:
def my_decorator(func):
def wrapper():
print "Before the function runs"
func()
print "After the function runs"
return wrapper
## 写法1
@my_decorator
def my_func():
print "I am a stand-alone function"
## 写法1 调用my_func()即可
>> my_func
Before the function runs
I am a stand-alone function
After the function runs
上述写法即@XXX,代码中的写法1。当然,大家更熟悉的写法2是这样的,没有那一坨@XXX:
def my_decorator(func):
def wrapper():
print "Before the function runs"
func()
print "After the function runs"
return wrapper
## 写法2
def my_func():
print "I am a stand-alone function"
new_my_func = my_decorator(my_func)
## 写法2 调用new_my_func()即可
>> new_my_func
Before the function runs
I am a stand-alone function
After the function runs
基于这样的写法,我们实现了核心功能func()与外围装饰的分离。
Python用一个简单的@,实现了设计模式中的装饰器模式decorator。
更一般例子,下述代码在没有改变func的情况下,调用func()时执行了deco的内容:
def deco(fn):
print "I am %s!" % fn.__name__
@deco
def func():
pass
# output
>> func()
I am func!
# 没有执行func 函数 但是 deco 被执行了
一种更有趣的用法:汉堡包还是披萨?——嵌套decorator,举例如下
def bread(func):
def wrapper():
print "</''''''\>"
func()
print "<\______/>"
return wrapper
def ingredients(func):
def wrapper():
print "#tomatoes#"
func()
print "~salad~"
return wrapper
## 写法1
@bread
@ingredients
def sandwich(food="--ham--"):
print food
## 写法1调用sandwich()
>> sandwich()
#### outputs
# </''''''\>
# #tomatoes#
# --ham--
# ~salad~
# <\______/>
## 写法2
def sandwich(food="--ham--"):
print food
## 写法2调用my_sandwich
>> my_sandwich = bread(ingredients(sandwich))
>> my_sandwich()
#### outputs
# </''''''\>
# #tomatoes#
# --ham--
# ~salad~
# <\______/>
面包Bread在外层,蔬菜和沙拉Ingredients在中层,肉Ham在内层,我们得到了汉堡。
而把ingredients和bread反过来,蔬菜和沙拉Ingredients在外层,面包Bread在中层,肉在内层,我们得到了披萨:
@ingredients
@bread
def sandwich(food="--ham--"):
print food
# outputs:
# #tomatoes#
# </' ' ' ' ' '\>
# --ham--
# <\______/>
# ~salad~
所有例子来源于:Python 装饰器使用指南 - SegmentFault 思否