虽然我喜欢认为自己是一个相当称职的Python程序员,但我始终无法理解该语言的一个方面是装饰器。

我知道它们是什么(表面上),我读过教程,例子,关于Stack Overflow的问题,我理解语法,可以自己写,偶尔使用@classmethod和@staticmethod,但我从来没有想过在我自己的Python代码中使用装饰器来解决问题。我从来没有遇到过这样的问题:“嗯……这看起来像是装修师的工作!”

所以,我想知道你们是否可以提供一些在你们自己的程序中使用装饰器的例子,希望我能有一个“啊哈!”的时刻,并得到它们。


当前回答

我使用装饰器进行类型检查参数,这些参数通过一些RMI传递给我的Python方法。因此,与其重复相同的参数计数,一遍又一遍地抛出异常。

例如,不要:

def myMethod(ID, name):
    if not (myIsType(ID, 'uint') and myIsType(name, 'utf8string')):
        raise BlaBlaException() ...

我只是声明:

@accepts(uint, utf8string)
def myMethod(ID, name):
    ...

并且接受()为我做了所有的工作。

其他回答

我使用装饰器进行类型检查参数,这些参数通过一些RMI传递给我的Python方法。因此,与其重复相同的参数计数,一遍又一遍地抛出异常。

例如,不要:

def myMethod(ID, name):
    if not (myIsType(ID, 'uint') and myIsType(name, 'utf8string')):
        raise BlaBlaException() ...

我只是声明:

@accepts(uint, utf8string)
def myMethod(ID, name):
    ...

并且接受()为我做了所有的工作。

对于nosetests,你可以编写一个装饰器,它提供一个带有几组参数的单元测试函数或方法:

@parameters(
   (2, 4, 6),
   (5, 6, 11),
)
def test_add(a, b, expected):
    assert a + b == expected

我使用下面的装饰器来使函数线程安全。它使代码更具可读性。它几乎类似于John Fouhy提出的方法,但不同之处在于它只处理一个函数,不需要显式地创建一个锁对象。

def threadsafe_function(fn):
    """decorator making sure that the decorated function is thread safe"""
    lock = threading.Lock()
    def new(*args, **kwargs):
        lock.acquire()
        try:
            r = fn(*args, **kwargs)
        except Exception as e:
            raise e
        finally:
            lock.release()
        return r
    return new

class X:
    var = 0

    @threadsafe_function     
    def inc_var(self):
        X.var += 1    
        return X.var

我使用装饰器主要是为了计时

def time_dec(func):

  def wrapper(*arg):
      t = time.clock()
      res = func(*arg)
      print func.func_name, time.clock()-t
      return res

  return wrapper


@time_dec
def myFunction(n):
    ...

装饰器用于您希望透明地“包装”附加功能的任何内容。

Django使用它们在视图函数中包装“登录必需”的功能,以及注册过滤器函数。

可以使用类装饰器将命名日志添加到类中。

任何可以“附加”到现有类或函数行为上的足够通用的功能都可以用作装饰。

在Python-Dev新闻组中也有关于用例的讨论,PEP 318—函数和方法的装饰器。