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

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

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


当前回答

我使用这个装饰器来修复参数

def fill_it(arg):
    if isinstance(arg, int):
        return "wan" + str(arg)
    else:
        try:
            # number present as string
            if str(int(arg)) == arg:
                return "wan" + arg
            else:
                # This should never happened
                raise Exception("I dont know this " + arg)
                print "What arg?"
        except ValueError, e:
            return arg

def fill_wanname(func):
    def wrapper(arg):
        filled = fill_it(arg)
        return func(filled)
    return wrapper

@fill_wanname
def get_iface_of(wanname):
    global __iface_config__
    return __iface_config__[wanname]['iface']

当我重构一些函数时,需要传递参数“wanN”,但在我的旧代码中,我只传递N或“N”

其他回答

装饰器既可以用来定义函数的属性,也可以用作修改函数的样板;它们可能返回完全不同的函数,但这是违反直觉的。看看这里的其他响应,最常见的用途之一似乎是限制一些其他进程的范围——无论是日志记录、概要分析、安全检查等等。

CherryPy使用对象调度将url匹配到对象,并最终匹配到方法。这些方法上的装饰符表示是否允许CherryPy使用这些方法。例如,改编自教程:

class HelloWorld:

    ...

    def secret(self):
        return "You shouldn't be here."

    @cherrypy.expose
    def index(self):
        return "Hello world!"

cherrypy.quickstart(HelloWorld())

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

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):
    ...

我使用这个装饰器来修复参数

def fill_it(arg):
    if isinstance(arg, int):
        return "wan" + str(arg)
    else:
        try:
            # number present as string
            if str(int(arg)) == arg:
                return "wan" + arg
            else:
                # This should never happened
                raise Exception("I dont know this " + arg)
                print "What arg?"
        except ValueError, e:
            return arg

def fill_wanname(func):
    def wrapper(arg):
        filled = fill_it(arg)
        return func(filled)
    return wrapper

@fill_wanname
def get_iface_of(wanname):
    global __iface_config__
    return __iface_config__[wanname]['iface']

当我重构一些函数时,需要传递参数“wanN”,但在我的旧代码中,我只传递N或“N”

我使用下面的装饰器来使函数线程安全。它使代码更具可读性。它几乎类似于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

Twisted库将装饰器与生成器结合使用,让人误以为异步函数是同步的。例如:

@inlineCallbacks
def asyncf():
    doStuff()
    yield someAsynchronousCall()
    doStuff()
    yield someAsynchronousCall()
    doStuff()

使用这种方法,原本被分解成大量小回调函数的代码可以很自然地编写为一个块,使其更容易理解和维护。