装饰器是一个函数,其主要用途是包装另一个函数或类。这种包装的目的是透明地修改或增强被包装对象的形为。表示装饰器的特殊符号是@,
@trace
def square(x):
return x * x
等价于
def square(x):
return x * x
square = trace(square)
示例:
1 对带参数的函数进行装饰
def deco(func):
def _deco(a, b):
print("before myfunc() called.")
ret = func(a, b)
print("after myfunc() called. result: %s" % ret)
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a + b
myfunc(1, 2)
更加通用的函数装饰器
def logpath(func):
def with_logging(*args, **kwargs):
print "Entering %s.%s" % (args[0].__class__.__name__, func.__name__)
return func(*args, **kwargs)
return with_logging
class Test:
@logpath
def function_one(self):
pass
@logpath
def function_two(self, a, b):
pass
Test().function_one()
Test().function_two(1, 2)
2 带参数的装饰器
def deco(arg):
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, arg))
func()
print(" after %s called [%s]." % (func.__name__, arg))
return __deco
return _deco
@deco("mymodule")
def myfunc():
print(" myfunc() called.")
实际上, deco("mymodule")的返回值为_deco, @_deco是一个函数装饰器
一个有趣的应用如下:
class locker:
def __init__(self):
print("locker.__init__() should be not called.")
@staticmethod
def acquire():
print("locker.acquire() called.")
@staticmethod
def release():
print(" locker.release() called.")
def deco(cls):
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, cls))
cls.acquire()
try:
return func()
finally:
cls.release()
return __deco
return _deco
@deco(locker)
def myfunc():
print(" myfunc() called.")
myfunc()
functools模块wraps装饰器
这是一个很有用的装饰器。函数是有几个特殊属性比如函数名,在被装饰后,会变成包装函数的属性。
例如
from functools import wraps
def logpath(func):
#@wraps(func)
def with_logging(*args, **kwargs):
print "Entering %s.%s" % (args[0].__class__.__name__, func.__name__)
return func(*args, **kwargs)
return with_logging
class Test:
@logpath
def function_one(self):
pass
@logpath
def function_two(self, a, b):
pass
Test().function_one()
Test().function_two(1, 2)
print Test().function_one.__name__ #with_logging
print Test().function_two.__name__ #with_logging
然而:
from functools import wraps
def logpath(func):
@wraps(func)
def with_logging(*args, **kwargs):
print "Entering %s.%s" % (args[0].__class__.__name__, func.__name__)
return func(*args, **kwargs)
return with_logging
class Test:
@logpath
def function_one(self):
pass
@logpath
def function_two(self, a, b):
pass
Test().function_one()
Test().function_two(1, 2)
print Test().function_one.__name__ #function_one
print Test().function_two.__name__ #function_two
参考文献:
1, http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html
2, http://stackoverflow.com/questions/308999/what-does-functools-wraps-do