Python装饰器 - 类中的__call__

时间:2013-10-21 14:51:31

标签: python python-decorators

我试图理解Python装饰器,我试图为这个编写一个等效的程序:

class myDecorator(object):
   def __init__(self, f):
      print ("inside myDecorator.__init__()")
      f() # Prove that function definition has completed

   def __call__(self):
      print ("inside myDecorator.__call__()")

@myDecorator
def aFunction():
   print ("inside aFunction()")

print ("Finished decorating aFunction()")

aFunction()

问题是我不了解如何通过最后调用__call__来调用类的aFunction()方法。

aFunction()取代myDecorator.__call__(aFunction)。 你能帮我么?没有装饰者的等效程序怎么样?

谢谢!

5 个答案:

答案 0 :(得分:8)

代码的输出是

inside myDecorator.__init__()
inside aFunction()
Finished decorating aFunction()
inside myDecorator.__call__()

首先,你知道吗,@ decorator语法是什么意思?

@decorator
def function(a):
    pass

只是另一种说法:

def function(a):
    pass
function = decorator(function)

所以,在你的情况下

@myDecorator
def aFunction():
   print ("inside aFunction()")

意味着

def aFunction():
    print ("inside aFunction()")
aFunction = myDecorator(aFunction)

首先,您基本上创建了myDecorator类的新实例,调用它的构造函数(__init__)并向其传递aFunction函数对象。然后,它执行打印和给定的功能。此外,请注意,这是在解释器加载函数时发生的,而不是在执行时,所以如果你从这个文件导入一些东西,它将会 然后执行,而不是使用或呼叫。

然后,执行aFunction(),当aFunction仍然引用myDecorator实例时,会调用myDecorator的__call__方法执行。请注意,f()在这种情况下与f.__call__(f)的含义相同,因为__call__方法用于启用和覆盖默认对象的调用行为(简化中,任何对象都可以调用当它定义了__call__方法时。

如果要在调用时执行aFunction,则应将其分配给__init__中的实例变量,并在myDecorator的__call__中调用它。

答案 1 :(得分:1)

afunction正被类myDecorator的实例替换。该类具有__call__方法,因此可以像函数一样调用实例。因此,假设它的签名是兼容的(通常装饰器返回使用*args**kwargs的东西),该实例可以用作原始函数的替代。

通常__call__方法会调用包装函数。在__init__中执行此操作通常是不正确的; __init__应该将对包装函数的引用存储为实例属性,以便__call__可以调用它。

答案 2 :(得分:1)

这就是装饰器的全部目的:用装饰器返回的函数替换(或更常见地,换行)函数。在您的情况下,aFunction正在替换为myDecorator的实例,因此当您调用aFunction()时,您实际上正在调用该实例:并且在Python中,调用类实例会调用其__call__ 1}}方法。

定义一个装饰函数与此完全相同:

def aFunction():
    print("inside aFunction()")
aFunction = myDecorator(aFunction)

当然,通常情况下,包装函数会在执行任何操作后调用原始函数。

答案 3 :(得分:1)

这是一个修复:

class myDecorator(object):
   def __init__(self, f):
      print ("inside myDecorator.__init__()")
      self.f = f #Store the function being wrapped

   def __call__(self):
      print ("inside myDecorator.__call__()")
      self.f() # Call the wrapped function

答案 4 :(得分:0)

你好,正确的方法是这样的 您有一个元类> ---装饰类>->实际类

    class Meta(type):
        """ Metaclass  """

        def __call__(cls, *args, **kwargs):
            instance = super(Meta, cls).__call__(*args, **kwargs)
            return instance

        def __init__(cls, name, base, attr):
            super(Meta, cls).__init__(name, base, attr)


    class counted(metaclass=Meta):

        """ counts how often a function is called """

        def __init__(self, func):
            self.func = func

        def __call__(self, *args, **kwargs):
            print("Timer Start ")
            Tem = self.func(*args, **kwargs)
            print("Timer End {} ".format(Tem))
            return Tem


    class Test(object):

        def __init__(self, *args, **kwargs):
            pass

        @counted
        def methodA():
            print("Method A")
            return "1111"


    if __name__ == "__main__":
        obj = Test()
        obj.methodA()