http://blog.gusibi.com/post/python-decorator/
对一个已有的模块做一些“修饰工作”,所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能)侵入到原有的模块中的代码里去
def my_decorator(func):
def wrapper():
print "Before the function runs"
func()
print "After the function runs"
return wrapper
def my_func():
print "I am a stand alone function"
>> my_func()
# output
I am a stand alone function
# 然后,我们在这里装饰这个函数
# 将函数传递给装饰器,装饰器将动态地将其包装在任何想执行的代码中,然后返回一个新的函数
>> my_func = my_decorator(my_func)
>> my_func()
#output
Before the function runs
I am a stand alone function
After the function runs
# 也可以这么写
@ my_decorator
def my_func():
print "I am a stand alone function"
>> my_func()
#output
Before the function runs
I am a stand alone function
After the function runs
8 多个装饰器
装饰器可以嵌套使用
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
8.0.1 outputs:
#嵌套两个装饰器
>> sandwich = bread(ingredients(sandwich)) //执行顺序,从左往右,先执行bread(), 把ingredients(sandwich)作为一个整体,当作bread()的参数
>> sandwich()
8.0.2 outputs:
```
</''''''\>
#tomatoes#
--ham--
~salad~
<\______/>
```
更简单的写法
@bread
@ingredients
def sandwich(food="--ham--"):
print food
装饰器的顺序是很重要的
@ingredients
@bread
def sandwich(food="--ham--"):
print food
# outputs:
```
#tomatoes#
</' ' ' ' ' '\>
--ham--
<\______/>
~salad~
```
9 Decorator 的本质
首先看一下这段代码
def deco(fn):
print "I am %s!" % fn.__name__
@deco
def func():
pass
# output
I am func!
# 没有执行func 函数 但是 deco 被执行了
在用某个@decorator来修饰某个函数func时
@decorator
def func():
pass
其解释器会解释成下面这样的语句:
func = decorator(func)
其实就是把一个函数当参数传到另一个函数中,然后再回调 但是值得注意的是装饰器必须返回一个函数
========================
http://www.cnblogs.com/itech/archive/2011/12/31/2308766.html
装饰器有两种形式:
def foo():
pass
相当于:
pass
foo = A(foo) #一次函数调用
第二种为带参数的:
def foo():
pass
则相当于:
pass
foo = A(arg)(foo) #两次函数调用
可以看出第一种的装饰器是个返回函数的函数,第二种的装饰器是个返回函数的函数的函数。
python中的decorator可以多个同时使用,如下:
@B
@C
def f (): pass
# it is same as below
def f(): pass
f = A(B(C(f)))
三 Python中常用的decorator实例
decorator通常用来在执行前进行权限认证,日志记录,甚至修改传入参数,或者在执行后对返回结果进行预处理,甚至可以截断函数的执行等等。
实例1:
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print (func.__name__() + " was called")
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
print (f.__name__) # prints 'f'
print (f.__doc__) # prints 'does some math'
注意functools.wraps()函数的作用:调用经过装饰的函数,例如foo = A(foo),调用装饰后的函数foo
相当于调用一个新函数,那查看函数参数,注释,甚至函数名的时候,就只能看到装饰器的相关信息,被包装函数的信息被丢掉了。
而wraps则可以帮你转移这些信息,参见http://stackoverflow.com/questions/308999/what-does-functools-wraps-do
参考:
http://www.cnblogs.com/Lifehacker/archive/2011/12/20/3_useful_python_decorator.html#2277951
===========================================================
http://www.cnblogs.com/xupeizhi/archive/2013/02/07/2908600.html
http://coolshell.cn/articles/11265.html
http://www.artima.com/weblogs/viewpost.jsp?thread=240808
首先,什么是函数修饰符?函数修饰符就是对原有函数做一层包装。比如有以下两个函数:
- def func1():
- print 'I am function func1'
- def func2():
- print 'I am function func2'
现在我们想为这两个函数增加一段共同的操作,这时就可以使用函数修饰符。首先我们定义一个修饰函数,先不做任何处理,仅仅打印一条横线:
def de( f ) def call_(): print '-------------------------------' //新功能 return f() //原始功能 return _call_ //返回函数对象
使用这个修饰符:
def de( f ): def _call_(): print '-------------------------------' return f() return _call @de def func1(): print 'I am function func1' @de def func2(): print 'I am function func2' if name = '__main__': func1() func2()
运行结果为:
-------------------------------
I am function func1
-------------------------------
I am function func2
可以看到,修饰符起作用了。
注意:
1.修饰符等价于包装调用:
@de
def func1:
等价于
func1 = de( func1 ) //原始功能func1被作为参数传递, 同时执行de()函数
2.修饰函数必须返回一个“可调用对象”:
def de( f ):
def call_():
return f()
return _call # 返回的是一个函数体,而非调用_call_()
下一个问题:如果各个被修饰函数有不同的参数,怎么处理呢?例如:
def func1( lst1, lst2 ): # 合并两个list,并打印各项 for item in lst1+lst2: print item def func2( dic ): # 循环dict,打印各key-value for k, v in dic.items(): print k, v
这两个函数参数不同,又都没有异常处理,现在我们想加上异常处理,使用修饰符这样处理:
import sys import traceback def de( f ): def _call( *args, **kwargs ): try: return f( *args , **kwargs ) except: print 'param type error' return _call
@de def func1( lst1, lst2 ): for item in lst1+lst2: print item @de def func2( dic ): for k, v in dic.items(): print k, v
if __name__ == '__main__': func1( [1,2], [3,4] ) func2( [1,2] )
这里使用了可变参数*args和**kwargs,这样会把所有接收来的参数,原样不动的再转给原函数,是惯用法。
以上程序运行结果:
1
2
3
4
param type error //因为func2的参数是一个dic,而实参[1, 2]是一个list
==========
需要注意的:
1. 函数先定义,再修饰它;反之会编译器不认识;
2. 修饰符“@”后面必须是之前定义的某一个函数;
3. 每个函数只能有一个修饰符,大于等于两个则不可以。
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
return wrapper
@my_decorator
def example():
"""Docstring"""
print 'Called example function'
example()
print example.__name__
print example.__doc__
输出:
Calling decorated function
Called example function
example
Docstring
代码使用 @functools.wraps 装饰将要返回的包裹函数 wrapper,使得他的 __name__, __doc__ 和 __module__ 属性与被装饰函数 examle()完全相同, 这样虽然最终调用的是经过装饰的 example() 函数,但是某些属性还是得到了维护。
如果不使用 @wraps(f) , 输出结果:
Calling decorated function
Called example function
example
None