python装饰器Decorators

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

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__其中一个的类加上其他的比较方法,这是一个类装饰器。

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 装饰类无限递归]

时间: 2024-07-29 07:31:04

python装饰器Decorators的相关文章

关于python装饰器(Decorators)最底层理解的一句话

一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.html 一步步教你理解Python装饰器 我作完了全部的测试.

Python 装饰器学习心得

最近打算重新开始记录自己的学习过程,于是就捡起被自己废弃了一年多的博客.这篇学习笔记主要是记录近来看的有关Python装饰器的东西. 0. 什么是装饰器? 本质上来说,装饰器其实就是一个特殊功能的函数,这个特殊的功能就是:装饰另一个函数.举一个最简单的例子来说: 1 def identify(f): 2 print 'Decorator identify called.' 3 return f 这里identify其实是一个装饰器,这个装饰器对输入的参数f不进行任何修饰,然后返回这个参数.其中的

Python装饰器的学习笔记(转载)

Python装饰器的学习笔记 2017-05-18 程序员共读 来自:标点符的<Python装饰器的学习笔记> 链接:http://www.biaodianfu.com/python-decorator.html 原文:http://stackoverflow.com/questions/739654/how-to-make-a-chain-of-function-decorators-in-python#answer-1594484 装饰器(decorator)是一种高级Python语法.可

Python装饰器完全解读

1 引言 装饰器(Decorators)可能是Python中最难掌握的概念之一了,也是最具Pythonic特色的技巧,深入理解并应用装饰器,你会更加感慨——人生苦短,我用Python. 2 初步理解装饰器 2.1 什么是装饰器 在解释什么是装饰器之前,我们有必要回顾一下Python中的一些思想和概念.我们都知道,Python是一门面向对象的语言,Python基本思想就是一些皆对象,数据类型是对象.类是对象.类实例也是对象……对于接下来我们要说的装饰器而言,最重要的是,函数也是对象! 你没看错,函

python装饰器 语法糖

简介: 装饰器(Decorators)是 Python 的一个重要部分.简单地说:他们是修改其他函数的功能的函数. 比如说我们写flask,路由就是用装饰器定义的.如果写权限控制,那么权限控制一般也是由装饰器来实现的.日志记录,一般也可以通过装饰器来实现. 简单说,就是为了给某些函数增加一种或几种功能的做法. 下面举例实现. 一:基本函数 1.源码 from time import sleep def watch_movie(): print('看电影') sleep(3) print('The

5.初识python装饰器 高阶函数+闭包+函数嵌套=装饰器

一.什么是装饰器? 实际上装饰器就是个函数,这个函数可以为其他函数提供附加的功能. 装饰器在给其他函数添加功能时,不会修改原函数的源代码,不会修改原函数的调用方式. 高阶函数+函数嵌套+闭包 = 装饰器 1.1什么是高阶函数? 1.1.1函数接收的参数,包涵一个函数名. 1.1.2 函数的返回值是一个函数名. 其实这两个条件都很好满足,下面就是一个高阶函数的例子. def test1(): print "hamasaki ayumi" def test2(func): return t

python装饰器通俗易懂的解释!

python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说明一下: 小P闲来无事,随便翻看自己以前写的一些函数,忽然对一个最最最基础的函数起了兴趣: 1 def sum1(): 2 sum = 1 + 2 3 print(sum) 4 sum1() 此时小P想看看这个函数执行用了多长时间,所以写了几句代码插进去了: 1 import time 2 3 def

python装饰器1

第八步:让装饰器带 类 参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # -*- coding:gbk -*- '''示例8: 装饰器带类参数''' class locker:     def __init__(self):         print("locker.__init__() should be not called.")   

Python装饰器由浅入深

装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们以装饰函数为例子介绍其用法.要理解在Python中装饰器的原理,需要一步一步来.本文尽量描述得浅显易懂,从最基础的内容讲起. (注:以下使用Python3.5.1环境) 一.Python的函数相关基础 第一,必须强调的是python是从上往下顺序执行的,而且碰到函数的定义代码块是不会立即执行它的,只