You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么使用类作为方法装饰器时args参数中不存在self?

问题成因

本质是Python的描述符协议实现差异导致的:

  • 普通Python函数原生实现了__get__方法,符合描述符规范。当你用函数类型的装饰器包装类方法时,返回的wrapper仍然是函数对象,访问实例的对应方法时,会自动触发描述符绑定逻辑,将实例对象作为第一个参数self注入到参数列表中,所以你能在args[0]拿到self。
  • 你自定义的DecoratorClass类没有实现__get__方法,不满足方法绑定的要求。当你访问实例的count_b属性时,直接返回的是DecoratorClass的实例对象,调用它的__call__方法时不会自动注入实例作为第一个参数,因此args是空元组,访问args[0]就触发了索引越界错误。

解决方法

给DecoratorClass实现__get__方法,兼容描述符协议的绑定逻辑即可,修正后的代码如下:

import functools
from types import MethodType


class DecoratorClass:
    def __init__(self, func):
        functools.update_wrapper(self, func)
        self.func = func                    
    
    # 新增__get__方法实现描述符协议
    def __get__(self, instance, owner):
        if instance is None:
            return self
        # 将当前装饰器实例绑定到调用方实例,返回绑定后的方法
        return MethodType(self, instance)
                        
    def __call__(self, *args, **kwargs):
        # 此时args[0]就是被绑定的self对象
        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()

运行后两个方法都可以正常输出,不会再触发索引错误。


内容的提问来源于stack exchange,提问作者Dominick Pastore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 16:27:03