Python修饰器

一. 定义

Python修饰器(Decorator)是一种高级Python语法。在设计模式中,修饰器模式使得函数保持原有的对外接口,同时可以动态的添加新的功能,比较常见的例子是Java中IO Stream的操作。关于Python Decorator是否与修饰器模式相同在此文中有讨论,作者认为Python Decorator更类似C中的宏,原文:

Indeed, you can use Python decorator to implement the Decorator pattern, but that's an extremely limited use of it. Python decorator, I think, are best equaled to macros.

我的理解是作者的意思是Python Decorator可以实现一些内置的函数流程控制,不过这点并没有理解很深刻。

从Stackoverflow排名很高的一篇提问看,由于Python中一切皆对象的设计原则,函数同样是一种对象,因此允许function call function的形式存在,也就是出于原函数功能不可改变的设计考虑(也可能是没有源码),提供增强版功能的调用:(本文大部分实例来自stackoverflow问题答复,有兴趣可详细参考)

def doSomethingBefore(func): 
    print "I do something before then I call the function you gave me"
print func()
doSomethingBefore(scream)

而decorator实际是把上述的手写编码调用方式修改为一种更为优雅的方式:

def doSomethingBefore(func):
    def _doSomething(*args, **kw):
        # do sth
        func(*args, **kw)
    return _doSomething
@doSomethingBefore
my_func()

二. 语法

1.最简单的语法(摘自stackoverflow上答复)

# The decorator to make it bold
def makebold(fn):
    # The new function the decorator returns
    def wrapper():
        # Insertion of some code before and after
        return "<b>" + fn() + "</b>"
    return wrapper

    @makebold
    def say():
        return "hello"
    print say()
    # output: <b>hello</b>

代码是自解释的。

2.传入参数

def decorator(function):
    def _decorate(name, *args, **kw):
        print 'Decorate  %s Begin' % name
        res = function(*args, **kw)
        print 'Decorate  %s End' % name
        return res
    return _decorate
def f(count):
    print 'Make Count %d' % count
@decorator
def f2(count):
    print 'Make Count %d' % count
f(10)
print '\n'
f2('linpingta', 10)

传入name参数作为decorator处理,其余参数作为function本身处理应用,这里用变参的原因是可能decorator需要去做的是一段公共的操作,具体可见“三。场景及其它”,不需要为每个函数实现一段单独的参数传递。

3.应用于类函数

具体见stackverlow的回答,主要要在decorator中加入self参数。

三. 场景及其它

在我工作中遇到的一个decorator应用场景是,我在对Facebook广告API调用时,由于网络以及各种原因,都可能出现失败的情况。如果这种失败是由于逻辑设计问题,那么需要相关的错误处理,但如果这种错误由于网络连接操作(比如短时间内Facebook API调用过于频繁),那么经过一段时间的等待重试就可以解决。而且网络状态或者API调用的错误是无法预知的,因此重试机制有必要存在。 在这里的设计中,我使用了decorator实现Facebook侧和数据库侧的重试逻辑,同时考虑API参数彼此不同,因此使用变参形式(见二.2)

从Python语言本身看,比如@staticmethod, @classmethod 从Django应用看,它的caching机制和权限控制是通过decorator实现的

总体而言,Decorator是一种Python常用的工具,可以在需要的时候考虑它。