使用类作为装饰器时,为啥 'self' 不在 args 中? [复制]

Posted

技术标签:

【中文标题】使用类作为装饰器时,为啥 \'self\' 不在 args 中? [复制]【英文标题】:Why is 'self' not in args when using a class as a decorator? [duplicate]使用类作为装饰器时,为什么 'self' 不在 args 中? [复制] 【发布时间】:2021-11-16 04:51:27 【问题描述】:

Class method decorator with self arguments? 的最佳答案(答案直接链接:https://***.com/a/11731208)描述了装饰器在装饰方法时如何访问对象的属性。

我尝试将它应用到我自己的代码中,但意识到它仅在使用函数作为装饰器时才有效。出于某种原因,当使用类作为装饰器时,参数元组不再包含 self 对象。为什么会发生这种情况,还有其他方法可以访问包装方法的self

演示:

import functools


class DecoratorClass:
    def __init__(self, func):
        functools.update_wrapper(self, func)
        self.func = func                    
                        
    def __call__(self, *args, **kwargs):
        print("args:", args)            
        print("kwargs:", kwargs)
        print("Counting with:", args[0].name)
        self.func(*args, **kwargs)           
                                  

def decorator_func(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("args:", args)     
        print("kwargs:", kwargs)
        print("Counting with:", args[0].name)
        func(*args, **kwargs)                
    return wrapper           
                  

class Counter:
    def __init__(self, name, count):
        self.name = name            
        self.count = count
                          
    @decorator_func
    def count_a(self):
        for i in range(self.count):
            print(i)               
                    
    @DecoratorClass
    def count_b(self):
        for i in range(self.count):
            print(i)               
                    

c = Counter('my counter', 3)
                            
c.count_a()
print()    
c.count_b()

输出:

args: (<__main__.Counter object at 0x7f4491a21970>,)
kwargs: 
Counting with: my counter
0
1
2

args: ()
kwargs: 
Traceback (most recent call last):
  File "./test2.py", line 48, in <module>
    c.count_b()
  File "./test2.py", line 14, in __call__
    print("Counting with:", args[0].name)
IndexError: tuple index out of range

【问题讨论】:

【参考方案1】:

这是一个已知问题(请参阅here)。不久前,在我的一个项目中实现类装饰器时,我实际上遇到了同样的问题。

为了解决这个问题,我将以下方法添加到我的课程中 - 您也可以将其添加到您的 DecoratorClass,然后它应该可以毫无意外地工作。

def __get__(self, instance, owner):
    """
    Fix: make our decorator class a decorator, so that it also works to
    decorate instance methods.
    https://***.com/a/30105234/10237506
    """
    from functools import partial
    return partial(self.__call__, instance)

另外,请参阅链接的 SO 答案,了解为什么会这样。

【讨论】:

哦,很好的发现,我投票决定关闭它作为重复。 是的,不幸的是,我不知道我是否能够做到这一点。我也会投票决定将其作为副本关闭。

以上是关于使用类作为装饰器时,为啥 'self' 不在 args 中? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

当一个方法中有两个装饰器时,为啥 sphinx autodoc 会输出一个装饰器的文档字符串?

TypeError:在类中使用装饰器时,“staticmethod”对象不可调用

装饰器仅在装饰方法时有效,但在使用作为参数传递的方法调用装饰器时无效

使用Typescript和类组件装饰器时如何在Vue Router中传递props

使用装饰器时如何在 VueJS 中使用 Data 对象? “预计 'this' 将由类方法 'data' 使用。”

用类作为装饰器装饰函数!