【问题标题】:Python Decorators - __call__ in classPython 装饰器 - 类中的 __call__
【发布时间】:2013-10-30 03:17:20
【问题描述】:

我试图理解 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) 替换。 你能帮我么?没有装饰器的等效程序如何?

谢谢!

【问题讨论】:

    标签: python python-decorators


    【解决方案1】:

    你好正确的方法是这样的 你有一个元类 > --- Decoratorclass > --> 实际类

        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()
    

    【讨论】:

      【解决方案2】:

      这里有一个修复:

      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
      

      【讨论】:

      • 接受函数的参数使用 def __call__(self, *args,**kwargs): 并将它们传递给 f
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        你的代码的输出是

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

        首先,你知道这个@装饰器语法是什么意思吗?

        @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__ 方法时,任何对象都是可调用的)。

        如果你想在一个函数被调用的时候执行它,那么你应该把它赋值给__init__中的实例变量,然后在myDecorator的__call__中调用它。

        【讨论】:

          【解决方案5】:

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

          定义一个装饰函数完全等价于:

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

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

          【讨论】:

            猜你喜欢
            • 2023-03-23
            • 2015-01-03
            • 2015-03-24
            • 2019-09-20
            • 2010-10-14
            • 1970-01-01
            • 2011-04-28
            • 2012-02-09
            相关资源
            最近更新 更多