http://blog.csdn.net/pipisorry/article/details/41902599
Introduction
装饰器Decorators是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
装饰器为我们提供了一个增加已有函数或类的功能的有效方法。听起来是不是很像Java中的面向切面编程(Aspect-Oriented Programming)概念?两者都很简单,并且装饰器有着更为强大的功能。举个例子,假定你希望在一个函数的入口和退出点做一些特别的操作(比如一些安全、追踪以及锁定等操作)就可以使用装饰器。
装饰器是一个包装了另一个函数的特殊函数:主函数被调用,并且其返回值将会被传给装饰器,接下来装饰器将返回一个包装了主函数的替代函数,程序的其他部分看到的将是这个包装函数。
def timethis(func):
'''
Decorator that reports the execution time.
'''
pass
@timethis
def countdown(n):
while n > 0:
n -= 1
语法糖@标识了装饰器。
我们将用装饰器做一些更典型的操作:
import time
from functools import wraps
def timethis(func):
'''
Decorator that reports the execution time.
'''
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(func.__name__, end-start)
return result
return wrapper
@timethis
def countdown(n):
while n > 0:
n -= 1
countdown(100000)
# ('countdown', 0.006999969482421875)
当你写下如下代码时:
@timethis
def countdown(n):
意味着你分开执行了以下步骤:
def countdown(n):
...
countdown = timethis(countdown)
装饰器函数中的代码创建了一个新的函数(正如此例中的wrapper函数),它用 *args 和 **kwargs 接收任意的输入参数,并且在此函数内调用原函数并且返回其结果。你可以根据自己的需要放置任何额外的代码(例如本例中的计时操作),新创建的包装函数将作为结果返回并取代原函数。
@decorator
def function():
print("inside function")
当编译器查看以上代码时,function()函数将会被编译,并且函数返回对象将会被传给装饰器代码,装饰器将会在做完相关操作之后用一个新的函数对象代替原函数。
Python装饰器要考虑装饰器本身的定义和被装饰器对象的定义。
对于无参数的装饰器,其装饰器函数的参数是要被装饰的函数对象名;
对于有参数的装饰器在调用时使用的是应用的参数,@timeStumpFunc_args(argv)的argv,已不再是要被装饰的函数对象名,所以必须在内部再定义一个函数getfunc()来接收要被装饰的函数对象。
需求?
装饰器的定义很是抽象,我们来看一个小例子。
def
foo():
'in foo()'
foo()
看看执行这个函数用了多长时间,可以这样做:
import
time
def
foo():
start
=
time.clock()
'in foo()'
end
=
time.clock()
'used:'
, end
-
start
foo()
考虑重新定义一个函数timeit,将foo的引用传递给他,然后在timeit中调用foo并进行计时,这样,我们就达到了不改动foo定义的目的
#!/usr/bin/env python # coding=gbk """ __title__ = '带参数和不带参数的timeStump' __author__ = 'pi' __mtime__ = '2014.12.12' """ from time import ctime def timeStumpFunc(func): """time stump decorator of func 不带参数的时间戳函数""" def wrappedFunc(*nkw): print("start_time %s" % ctime()) func(*nkw) print("end_time %s" % ctime()) return wrappedFunc def timeStumpFunc_args(args): """time stump decorator of func 不带参数的时间戳函数""" print "timeStump for function %s" % args def getFunc(func): def wrappedFunc(*nkw): print("start_time %s" % ctime()) func(*nkw) print("end_time %s" % ctime()) return wrappedFunc return getFunc @timeStumpFunc # @timeStumpFunc_args('do_sth') def do_sth(*nkw): print "%s" % nkw if __name__ == '__main__': do_sth('i you love')
不同装饰器和被装饰对象的例子
一、函数式装饰器:装饰器本身是一个函数
1.装饰函数:被装饰对象是一个函数
[1]装饰器无参数:
a.被装饰对象无参数:
1 >>> def test(func): 2 def _test(): 3 print 'Call the function %s().'%func.func_name 4 return func() 5 return _test 6 7 >>> @test 8 def say():return 'hello world' 9 10 >>> say() 11 Call the function say(). 12 'hello world' 13 >>>
b.被装饰对象有参数:
1 >>> def test(func): 2 def _test(*args,**kw): 3 print 'Call the function %s().'%func.func_name 4 return func(*args,**kw) 5 return _test 6 7 >>> @test 8 def left(Str,Len): 9 #The parameters of _test can be '(Str,Len)' in this case. 10 return Str[:Len] 11 12 >>> left('hello world',5) 13 Call the function left(). 14 'hello' 15 >>>
[2]装饰器有参数:
a.被装饰对象无参数:
1 >>> def test(printResult=False): 2 def _test(func): 3 def __test(): 4 print 'Call the function %s().'%func.func_name 5 if printResult: 6 print func() 7 else: 8 return func() 9 return __test 10 return _test 11 12 >>> @test(True) 13 def say():return 'hello world' 14 15 >>> say() 16 Call the function say(). 17 hello world 18 >>> @test(False) 19 def say():return 'hello world' 20 21 >>> say() 22 Call the function say(). 23 'hello world' 24 >>> @test() 25 def say():return 'hello world' 26 27 >>> say() 28 Call the function say(). 29 'hello world' 30 >>> @test 31 def say():return 'hello world' 32 33 >>> say() 34 35 Traceback (most recent call last): 36 File "<pyshell#224>", line 1, in <module> 37 say() 38 TypeError: _test() takes exactly 1 argument (0 given) 39 >>>
b.被装饰对象有参数:
1 >>> def test(printResult=False): 2 def _test(func): 3 def __test(*args,**kw): 4 print 'Call the function %s().'%func.func_name 5 if printResult: 6 print func(*args,**kw) 7 else: 8 return func(*args,**kw) 9 return __test 10 return _test 11 12 >>> @test() 13 def left(Str,Len): 14 #The parameters of __test can be '(Str,Len)' in this case. 15 return Str[:Len] 16 17 >>> left('hello world',5) 18 Call the function left(). 19 'hello' 20 >>> @test(True) 21 def left(Str,Len): 22 #The parameters of __test can be '(Str,Len)' in this case. 23 return Str[:Len] 24 25 >>> left('hello world',5) 26 Call the function left(). 27 hello 28 >>>
2.装饰类:被装饰的对象是一个类
[1]装饰器无参数:
a.被装饰对象无参数:
1 >>> def test(cls): 2 def _test(): 3 clsName=re.findall('(\w+)',repr(cls))[-1] 4 print 'Call %s.__init().'%clsName 5 return cls() 6 return _test 7 8 >>> @test 9 class sy(object): 10 value=32 11 12 13 >>> s=sy() 14 Call sy.__init(). 15 >>> s 16 <__main__.sy object at 0x0000000002C3E390> 17 >>> s.value 18 32 19 >>>
b.被装饰对象有参数:
1 >>> def test(cls): 2 def _test(*args,**kw): 3 clsName=re.findall('(\w+)',repr(cls))[-1] 4 print 'Call %s.__init().'%clsName 5 return cls(*args,**kw) 6 return _test 7 8 >>> @test 9 class sy(object): 10 def __init__(self,value): 11 #The parameters of _test can be '(value)' in this case. 12 self.value=value 13 14 15 >>> s=sy('hello world') 16 Call sy.__init(). 17 >>> s 18 <__main__.sy object at 0x0000000003AF7748> 19 >>> s.value 20 'hello world' 21 >>>
[2]装饰器有参数:
a.被装饰对象无参数:
1 >>> def test(printValue=True): 2 def _test(cls): 3 def __test(): 4 clsName=re.findall('(\w+)',repr(cls))[-1] 5 print 'Call %s.__init().'%clsName 6 obj=cls() 7 if printValue: 8 print 'value = %r'%obj.value 9 return obj 10 return __test 11 return _test 12 13 >>> @test() 14 class sy(object): 15 def __init__(self): 16 self.value=32 17 18 19 >>> s=sy() 20 Call sy.__init(). 21 value = 32 22 >>> @test(False) 23 class sy(object): 24 def __init__(self): 25 self.value=32 26 27 28 >>> s=sy() 29 Call sy.__init(). 30 >>>
b.被装饰对象有参数:
1 >>> def test(printValue=True): 2 def _test(cls): 3 def __test(*args,**kw): 4 clsName=re.findall('(\w+)',repr(cls))[-1] 5 print 'Call %s.__init().'%clsName 6 obj=cls(*args,**kw) 7 if printValue: 8 print 'value = %r'%obj.value 9 return obj 10 return __test 11 return _test 12 13 >>> @test() 14 class sy(object): 15 def __init__(self,value): 16 self.value=value 17 18 19 >>> s=sy('hello world') 20 Call sy.__init(). 21 value = 'hello world' 22 >>> @test(False) 23 class sy(object): 24 def __init__(self,value): 25 self.value=value 26 27 28 >>> s=sy('hello world') 29 Call sy.__init(). 30 >>>
二、类式装饰器:装饰器本身是一个类-借用__init__()和__call__()来实现职能
1.装饰函数:被装饰对象是一个函数
[1]装饰器无参数:
a.被装饰对象无参数:
1 >>> class test(object): 2 def __init__(self,func): 3 self._func=func 4 def __call__(self): 5 return self._func() 6 7 8 >>> @test 9 def say(): 10 return 'hello world' 11 12 >>> say() 13 'hello world' 14 >>>
b.被装饰对象有参数:
1 >>> class test(object): 2 def __init__(self,func): 3 self._func=func 4 def __call__(self,*args,**kw): 5 return self._func(*args,**kw) 6 7 8 >>> @test 9 def left(Str,Len): 10 #The parameters of __call__ can be '(self,Str,Len)' in this case. 11 return Str[:Len] 12 13 >>> left('hello world',5) 14 'hello' 15 >>>
[2]装饰器有参数
a.被装饰对象无参数:
1 >>> class test(object): 2 def __init__(self,beforeinfo='Call function'): 3 self.beforeInfo=beforeinfo 4 def __call__(self,func): 5 def _call(): 6 print self.beforeInfo 7 return func() 8 return _call 9 10 11 >>> @test() 12 def say(): 13 return 'hello world' 14 15 >>> say() 16 Call function 17 'hello world' 18 >>>
或者:
1 >>> class test(object): 2 def __init__(self,beforeinfo='Call function'): 3 self.beforeInfo=beforeinfo 4 def __call__(self,func): 5 self._func=func 6 return self._call 7 def _call(self): 8 print self.beforeInfo 9 return self._func() 10 11 12 >>> @test() 13 def say(): 14 return 'hello world' 15 16 >>> say() 17 Call function 18 'hello world' 19 >>>
b.被装饰对象有参数:
1 >>> class test(object): 2 def __init__(self,beforeinfo='Call function'): 3 self.beforeInfo=beforeinfo 4 def __call__(self,func): 5 def _call(*args,**kw): 6 print self.beforeInfo 7 return func(*args,**kw) 8 return _call 9 10 11 >>> @test() 12 def left(Str,Len): 13 #The parameters of _call can be '(Str,Len)' in this case. 14 return Str[:Len] 15 16 >>> left('hello world',5) 17 Call function 18 'hello' 19 >>>
或者:
1 >>> class test(object): 2 def __init__(self,beforeinfo='Call function'): 3 self.beforeInfo=beforeinfo 4 def __call__(self,func): 5 self._func=func 6 return self._call 7 def _call(self,*args,**kw): 8 print self.beforeInfo 9 return self._func(*args,**kw) 10 11 12 >>> @test() 13 def left(Str,Len): 14 #The parameters of _call can be '(self,Str,Len)' in this case. 15 return Str[:Len] 16 17 >>> left('hello world',5) 18 Call function 19 'hello' 20 >>>
2.装饰类:被装饰对象是一个类
[1]装饰器无参数:
a.被装饰对象无参数:
1 >>> class test(object): 2 def __init__(self,cls): 3 self._cls=cls 4 def __call__(self): 5 return self._cls() 6 7 8 >>> @test 9 class sy(object): 10 def __init__(self): 11 self.value=32 12 13 14 >>> s=sy() 15 >>> s 16 <__main__.sy object at 0x0000000003AAFA20> 17 >>> s.value 18 32 19 >>>
b.被装饰对象有参数:
1 >>> class test(object): 2 def __init__(self,cls): 3 self._cls=cls 4 def __call__(self,*args,**kw): 5 return self._cls(*args,**kw) 6 7 8 >>> @test 9 class sy(object): 10 def __init__(self,value): 11 #The parameters of __call__ can be '(self,value)' in this case. 12 self.value=value 13 14 15 >>> s=sy('hello world') 16 >>> s 17 <__main__.sy object at 0x0000000003AAFA20> 18 >>> s.value 19 'hello world' 20 >>>
[2]装饰器有参数:
a.被装饰对象无参数:
1 >>> class test(object): 2 def __init__(self,printValue=False): 3 self._printValue=printValue 4 def __call__(self,cls): 5 def _call(): 6 obj=cls() 7 if self._printValue: 8 print 'value = %r'%obj.value 9 return obj 10 return _call 11 12 13 >>> @test(True) 14 class sy(object): 15 def __init__(self): 16 self.value=32 17 18 19 >>> s=sy() 20 value = 32 21 >>> s 22 <__main__.sy object at 0x0000000003AB50B8> 23 >>> s.value 24 32 25 >>>
b.被装饰对象有参数:
1 >>> class test(object): 2 def __init__(self,printValue=False): 3 self._printValue=printValue 4 def __call__(self,cls): 5 def _call(*args,**kw): 6 obj=cls(*args,**kw) 7 if self._printValue: 8 print 'value = %r'%obj.value 9 return obj 10 return _call 11 12 13 >>> @test(True) 14 class sy(object): 15 def __init__(self,value): 16 #The parameters of _call can be '(value)' in this case. 17 self.value=value 18 19 20 >>> s=sy('hello world') 21 value = 'hello world' 22 >>> s 23 <__main__.sy object at 0x0000000003AB5588> 24 >>> s.value 25 'hello world' 26 >>>
Note:
1. @decorator后面不带括号时(也即装饰器无参数时),效果就相当于先定义func或cls,而后执行赋值操作func=decorator(func)或cls=decorator(cls);
2. @decorator后面带括号时(也即装饰器有参数时),效果就相当于先定义func或cls,而后执行赋值操作 func=decorator(decoratorArgs)(func)或cls=decorator(decoratorArgs)(cls);
3. 如上将func或cls重新赋值后,此时的func或cls也不再是原来定义时的func或cls,而是一个可执行体,你只需要传入参数就可调用,func(args)=>返回值或者输出,cls(args)=>object of cls;
4. 最后通过赋值返回的执行体是多样的,可以是闭包,也可以是外部函数;当被装饰的是一个类时,还可以是类内部方法,函数;
5. 另外要想真正了解装饰器,一定要了解func.func_code.co_varnames,func.func_defaults,func.func_argcount,通过它们你可以以func的定义之外,还原func的参数列表,详见Python多重装饰器中的最后一个例子中的ArgsType;另外关键字参数是因为调用而出现的,而不是因为func的定义,func的定义中的用等号连接的只是有默认值的参数,它们并不一定会成为关键字参数,因为你仍然可以按照位置来传递它们。
皮皮blog
内置装饰器
内置的装饰器有三个,分别是staticmethod、classmethod和property,作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。由于模块里可以定义函数,所以静态方法和类方法的用处并不是太多,除非你想要完全的面向对象编程。而属性也不是不可或缺的,Java没有属性也一样活得很滋润。从我个人的Python经验来看,我没有使用过property,使用staticmethod和classmethod的频率也非常低。
class
Rabbit(
object
):
def
__init__(
self
, name):
self
._name
=
name
@staticmethod
def
newRabbit(name):
return
Rabbit(name)
@classmethod
def
newRabbit2(
cls
):
return
Rabbit('')
@property
def
name(
self
):
return
self
._name
这里定义的属性是一个只读属性,如果需要可写,则需要再定义一个setter:
@name
.setter
def
name(
self
, name):
self
._name
=
name
functools模块提供了两个装饰器。[Python装饰器与面向切面编程]
wraps(wrapped[, assigned][, updated]):total_ordering(cls):
这个装饰器在特定的场合有一定用处,但是它是在Python 2.7后新增的。它的作用是为实现了至少__lt__、__le__、__gt__、__ge__其中一个的类加上其他的比较方法,这是一个类装饰器。
from:http://blog.csdn.net/pipisorry/article/details/41902599
ref:Python装饰器:简单装饰,带参数装饰与类装饰器
http://outofmemory.cn/code-snippet/1107/python-achieve-carry-parameter-decorator
Python decorators: metaprogramming with style