http://blog.csdn.net/pipisorry/article/details/41902599

Introduction

装饰器Decorators是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。装饰器用于在不改变原函数代码的情况下修改已存在的函数。常见场景是增加一句调试,或者为已有的函数增加log监控。

装饰器为我们提供了一个增加已有函数或类的功能的有效方法。听起来是不是很像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():

print 'in foo()'

foo()

看看执行这个函数用了多长时间,可以这样做:

import time

def foo():

start =time.clock()

print 'in foo()'

end =time.clock()

print '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 ctimedef timeStumpFunc(func):"""time stump decorator of func 不带参数的时间戳函数"""def wrappedFunc(*nkw):print("start_time %s" % ctime())func(*nkw)print("end_time %s" % ctime())return wrappedFuncdef timeStumpFunc_args(args):"""time stump decorator of func 不带参数的时间戳函数"""print "timeStump for function %s" % argsdef getFunc(func):def wrappedFunc(*nkw):print("start_time %s" % ctime())func(*nkw)print("end_time %s" % ctime())return wrappedFuncreturn getFunc@timeStumpFunc
# @timeStumpFunc_args('do_sth')
def do_sth(*nkw):print "%s" % nkwif __name__ == '__main__':do_sth('i you love')

皮皮blog

不同装饰器和被装饰对象的例子

一、函数式装饰器:装饰器本身是一个函数

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 >>> 
Note:当装饰器有参数时,即使你启用装饰器的默认参数,不另外传递新值进去,也必须有一对括号,否则编译器会直接将func传递给test(),而不是传递给_test()

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模块

functools模块提供了两个装饰器。[Python装饰器与面向切面编程]

wraps(wrapped[, assigned][, updated]):
这是一个很有用的装饰器。看过前一篇反射的朋友应该知道,函数是有几个特殊属性比如函数名,在被装饰后,上例中的函数名foo会变成包装函数的名字wrapper,如果你希望使用反射,可能会导致意外的结果。这个装饰器可以解决这个问题,它能将装饰过的函数的特殊属性保留。

total_ordering(cls):
这个装饰器在特定的场合有一定用处,但是它是在Python 2.7后新增的。它的作用是为实现了至少__lt__、__le__、__gt__、__ge__其中一个的类加上其他的比较方法,这是一个类装饰器。

皮皮blog

示例

在for循环中只运行其中的某个函数一次

def run_once(f):
    def wrapper(*args, **kwargs):
        if not wrapper.has_run:
            wrapper.has_run = True
            return f(*args, **kwargs)wrapper.has_run = False
    print('***')return wrapperdef run_once1(f):
    def wrapper(*args, **kwargs):
        nonlocal has_runif not has_run:
            has_run = True
            return f(*args, **kwargs)has_run = False
    print('***')return wrapper@run_once1
def my_function(foo, bar):
    print(foo + bar)return foo + bar

for i in range(100):
    my_function(1, 2)

[Efficient way of having a function only execute once in a loop]

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

利用装饰器给python的函数加上类型限制

[神坑·Python 装饰类无限递归]

python装饰器Decorators相关推荐

  1. python 装饰器(Decorators)原理说明

    本文目的是由浅入深地介绍python装饰器原理 装饰器(Decorators)是 Python 的一个重要部分 其功能是, 在不修改原函数(类)定义代码的情况下,增加新的功能 为了理解和实现装饰器,我 ...

  2. python 装饰器分类_Python 装饰器(Decorators) 超详细分类实例

    Python装饰器分类 Python 装饰器函数: 是指装饰器本身是函数风格的实现; 函数装饰器: 是指被装饰的目标对象是函数;(目标对象); 装饰器类 : 是指装饰器本身是类风格的实现; 类装饰器 ...

  3. python 装饰器 参数-python装饰器的详细解析

    什么是装饰器? python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能. 这个函数的特殊之处在于 ...

  4. python装饰器原理-Python装饰器完全解读

    1 引言 装饰器(Decorators)可能是Python中最难掌握的概念之一了,也是最具Pythonic特色的技巧,深入理解并应用装饰器,你会更加感慨--人生苦短,我用Python. 2 初步理解装 ...

  5. [译] 12步轻松搞定python装饰器 - 简书

    [译] 12步轻松搞定python装饰器 - 简书 呵呵!作为一名教python的老师,我发现学生们基本上一开始很难搞定python的装饰器,也许因为装饰器确实很难懂.搞定装饰器需要你了解一些函数式编 ...

  6. 【转】python装饰器

    什么是装饰器? python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能. 这个函数的特殊之处在于 ...

  7. Python高级特性: 12步轻松搞定Python装饰器

    12步轻松搞定Python装饰器 通过 Python 装饰器实现DRY(不重复代码)原则:  http://python.jobbole.com/84151/ 基本上一开始很难搞定python的装饰器 ...

  8. python装饰器参数讲解_python装饰器的详细解析

    写在前面: python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能. 这个函数的特殊之处在于它的 ...

  9. python 装饰器装饰类_5分钟的Python装饰器指南

    python 装饰器装饰类 重点 (Top highlight) There's no doubt that Python decorators are one of the more advance ...

  10. python中的类装饰器应用场景_这是我见过最全面的Python装饰器教程了!

    装饰器(Decorators)是 Python 的一个重要部分.简单地说:他们是修改其他函数的功能的函数.他们有助于让我们的代码更简短,也更Pythonic(Python范儿).在程序开发中经常使用到 ...

最新文章

  1. 驭势科技引入国家队战略注资,完成超10亿元人民币融资
  2. C#BindingSource用法、属性、事件
  3. c++ url下载图片
  4. Riding the Fences USACO 3.3 欧拉路径(dfs+floodfill)
  5. python 异步io_python之同步IO和异步IO
  6. ios 横向滚轮效果_ios横向菜单+页面滑动
  7. html与cgi脚本的配合使用
  8. 世界卫生组织高血压防治指南_建立对团队和组织的信任的指南
  9. html中%3csvg%3e标签的使用,微信小程序:使用svg
  10. C#需要在项目程序生成前后执行相关的事件
  11. 30.卷1(套接字联网API)---客户/服务器程序设计规范
  12. Android使用拖拽控件来布局界面并展示
  13. 拒绝版权流氓!阿里巴巴重磅发布免费商用字体
  14. 案例分析:如何从0到1对一款产品游戏化
  15. java wav合并_java – 如何将两个wav文件合并/合并到一个wav文件中?
  16. Multism14安装问题
  17. 车机蓝牙通话流程分析的流程分析
  18. git push简介
  19. 7-80 大炮打蚊子(C语言)
  20. python学习第十二天

热门文章

  1. Class.forName的作用以及为什么要用它【转】
  2. w3cSchool jquery学习
  3. 你真的了解分层架构吗?——写给被PetShop毒害的朋友们
  4. OpenGL学习笔记(一)OpenGL坐标变换
  5. 外壳程序(shell):命令解释器commond
  6. 开发框架:AdminLTE
  7. 看代码学知识之(1) 获取当前线程状态
  8. (摘要)100个伟大的商业理念:理念35:引爆流行
  9. cocos-2d iphone入门(二) cocos2d源代码生成查询文档
  10. 巧用BroadcastReceiver实现开机“自”启动