Python/装饰器

维基教科书,自由的教学读本
跳到导航 跳到搜索

Python的装饰器是高阶函数的语法糖。

属性装饰器(property decorator)的最简单例子:

>>> class Foo(object):
...     @property
...     def bar(self):
...         return 'baz'
...
>>> F = Foo()
>>> print F.bar
baz

上例是下述代码的语法糖:

>>> class Foo(object):
...     def bar(self):
...         return 'baz'
...     bar = property(bar)
...
>>> F = Foo()
>>> print F.bar
baz

泛型装饰器(generic decorator)的最简单例子:

>>> def decorator(f):
...     def called(*args, **kargs):
...         print 'A function is called somewhere'
...         return f(*args, **kargs)
...     return called
...
>>> class Foo(object):
...     @decorator
...     def bar(self):
...         return 'baz'
...
>>> F = Foo()
>>> print F.bar()
A function is called somewhere
baz

下述例子打印出函数的每次调用及其实参:

#define the Trace class that will be 
#invoked using decorators
class Trace(object):
    def __init__(self, f):
        self.f =f

    def __call__(self, *args, **kwargs):
        print "entering function " + self.f.__name__
        i=0
        for arg in args:
            print "arg {0}: {1}".format(i, arg)
            i =i+1
            
        return self.f(*args, **kwargs)

@Trace
def sum(a, b):
    print "inside sum"
    return a + b

>>> sum(3,2)
entering function sum
arg 0: 3
arg 1: 2
inside sum

或者用一个函数代替类作为装饰器:

def Trace(f):
    def my_f(*args, **kwargs):
        print "entering " +  f.__name__
        result= f(*args, **kwargs)
        print "exiting " +  f.__name__
        return result
    my_f.__name = f.__name__
    my_f.__doc__ = f.__doc__
    return my_f

#An example of the trace decorator
@Trace
def sum(a, b):
    print "inside sum"
    return a + b

#if you run this you should see
>>> sum(3,2)
entering sum
inside sum
exiting sum
5

装饰器是一个著名的设计模式,经常被用于有切面(aspect)需求的场景,如插入日志、性能测试、事务处理等。装饰器可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。

Python于是提供了一些语法糖来降低为使用装饰器而带来的源代码输入量。

import time
 
def timeit(func):
    def wrapper():
        start = time.clock()
        func()
        end =time.clock()
        print 'used:', end - start
    return wrapper
 
@timeit
def foo():
    print 'in foo()'
 
foo()

内置的装饰器有三个,分别是staticmethod、classmethod和property,分别把类中定义的实例方法变成静态方法、类方法和类属性。由于模块里可以定义函数,所以静态方法和类方法的用处并不是太多,除非你想要完全的面向对象编程。属性也不是不可或缺的。

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

    @name.setter
    def name(self, name):
        self._name = name

functools模块[编辑]

wraps(wrapped[, assigned][, updated]): 将装饰过的函数的特殊属性保留。

import time
import functools
 
def timeit(func):
    @functools.wraps(func)
    def wrapper():
        start = time.clock()
        func()
        end =time.clock()
        print 'used:', end - start
    return wrapper
 
@timeit
def foo():
    print 'in foo()'
 
foo()
print foo.__name__

total_ordering(cls):