创建可以看到当前类方法的装饰器

时间:2010-09-13 21:01:40

标签: python decorator class-method

你能在类中创建一个装饰器来查看类方法和变量吗?

装饰者在这里看不到:self.longcondition()

class Foo:
    def __init__(self, name):
        self.name = name

    # decorator that will see the self.longcondition ???
    class canRun(object):
            def __init__(self, f):
                self.f = f

            def __call__(self, *args):
                if self.longcondition(): # <-------- ???
                    self.f(*args)

    # this is supposed to be a very long condition :)
    def longcondition(self):
        return isinstance(self.name, str)

    @canRun # <------
    def run(self, times):
        for i in xrange(times):
            print "%s. run... %s" % (i, self.name)

3 个答案:

答案 0 :(得分:5)

没有必要将这个装饰器作为一个类来实现,并且不需要在Foo类的定义中实现它。以下就足够了:

def canRun(meth):
    def decorated_meth(self, *args, **kwargs):
        if self.longcondition():
            print 'Can run'
            return meth(self, *args, **kwargs)
        else:
            print 'Cannot run'
            return None
    return decorated_meth

使用该装饰器似乎有效:

>>> Foo('hello').run(5)
Can run
0. run... hello
1. run... hello
2. run... hello
3. run... hello
4. run... hello
>>> Foo(123).run(5)
Cannot run

答案 1 :(得分:1)

我之前的回答是匆忙做出的。如果您想要编写装饰器,则应该使用wraps模块中的functools。它会为你解决困难。

定义canRun装饰器的正确方法是:

from functools import wraps
def canRun(f):
  @wraps(f)
  def wrapper(instance, *args):
    if instance.longcondition():
      return f(instance, *args)
  return wrapper

canRun函数应该在类之外定义。

答案 2 :(得分:1)

你可以让它成为一个类,但你需要使用描述符协议

 import types

 class canRun(object):
    def __init__(self, f):
        self.f = f
        self.o = object  # <-- What the hell is this about? 

    def __call__(self, *args):
        if self.longcondition():
            self.f(*args)

    def __get__(self, instance, owner):
         return types.MethodType(self, instance)

当您想使用__call__方法使用类实例修饰类方法时,总是需要使用描述符。这样做的原因是只传递了一个self,它引用了装饰类的实例,而不是装饰方法的实例。