【问题标题】:Print out function arguments and values in __getattribute__ method在 __getattribute__ 方法中打印出函数参数和值
【发布时间】:2020-02-13 07:31:32
【问题描述】:

我正在尝试打印出实例每次调用函数时实例调用的函数名称和参数

我正在使用 getattribute 方法来实现这个,我的代码在下面

    def __getattribute__(self, attr):

        def newfunc(*args, **kwargs):

            print( "%r Calling %r with %r %r" % (self, attr, args, kwargs))


    return newfunc 

代码确实打印出函数的名称和参数,但没有执行 origin 方法,因为它返回一个新函数而不是调用旧函数。

我做了一些搜索,比如question,这个答案中的最高投票使用 dict 在字典中通过函数名检索函数,我试过了,但它导致递归称呼。

我的问题是。有没有办法在 __getattribute__method 中打印出函数的名称和参数?

或者有没有办法在每次实例调用其方法时打印出函数的名称和参数?


附言。除了使用装饰器,我知道我可以为此使用装饰器,但我不想把装饰器放在我使用的每个方法前面

【问题讨论】:

    标签: python-3.x getattribute


    【解决方案1】:

    由于您不想应用装饰器但仍需要“在__getattribute__ 方法中打印出函数的名称和参数” - 使用以下方法:

    为了避免__getattribute__方法的无限递归,它的实现应该总是调用同名的基类方法来访问它需要的任何属性。

    class A:
        def my_func(self, a, b):
            return a + b
    
        def __getattribute__(self, attr):
            def newfunc(*args, **kwargs):
                print("%r Calling %r with %r %r" % (self, attr, args, kwargs))
    
                return object.__getattribute__(self, attr)
            return newfunc
    
    a = A()
    a.my_func(1, 2)
    a.my_func(3, 4)
    

    样本输出:

    <__main__.A object at 0x116861710> Calling 'my_func' with (1, 2) {}
    <__main__.A object at 0x116861710> Calling 'my_func' with (3, 4) {}
    

    【讨论】:

      【解决方案2】:

      您的代码的主要且明显的问题是,您在任何时候都无法检索实例中的原始属性,这是 __getattribute__ 的工作 - 打破 __getattribute__ 是一种 100% 死的确保您的课程根本不起作用。

      所以,第一件事是调用超类上的工作__getattribute__ 来检索属性。

      那么你的代码中明显缺乏的第二部分是你甚至没有尝试从你的“打印机”函数中调用原始函数或方法。 我们将这样的调用放在其代码的末尾。

      完成后,请多加注意,例如,不要尝试返回包装在函数中的不可调用属性,因为那样会失败。

      处理好这三点后,它应该可以按您的预期工作:

      def __getattribute__(self, attr):
      
          original = super().__getattribute__(attr)
          if callable(original):
              def newfunc(*args,  **kwargs):
      
                  print( "%r Calling %r with %r %r" % (self, attr, args, kwargs))
                  return original(*args, **kwargs)
              return newfunc
          return original
      
      

      【讨论】:

      • 谢谢!它对我有用,我实际上尝试使用 getattr 调用该函数,但它不起作用
      • __getattr__ 仅针对实例上未找到的属性调用 - 它的目的是提供它单独公开的动态属性。相反,__getattribute__every 属性访问调用。 (并且__getattr__ 本身在object.__getattribute__ 内部被调用作为属性查找的一部分,而不是在它返回之后)