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

使用实例方法作为装饰器修饰类内方法时触发TypeError的问题

类内实例方法作为装饰器使用@语法糖报错的问题排查与解决

问题场景

使用Car类的实例方法decor作为装饰器修饰类内的car_details方法时,手动调用装饰逻辑(先创建实例再绑定方法)代码可正常运行,但使用@decor语法糖时触发错误:

TypeError: decor() missing 1 required positional argument: 'func'

手动可行的调用代码片段:

if __name__ == '__main__':
    car_type = input("Enter type of car: ")
    price = int(input("Enter price of car: "))
    obj = Car(car_type, price)
    decor = obj.decor
    details = obj.car_details
    tax = {1: "Yes", 2: "No"}
    to_apply = int(input("Select 1 for applying tax and 0 for No:"))
    ans = tax.get(to_apply)
    res = decor(details)
    res(ans)

报错的完整代码:

TYPE = {'hybrid': 'Hybrid', 'petrol': 'Petrol', 'deasel': 'Deasel'}

def tax_price(car_type):
    if car_type == 'hybrid':
        SGST = 300000
        GST = 500000
    elif car_type == 'petrol':
        SGST = 200000
        GST = 400000
    elif car_type == 'deasel':
        SGST = 100000
        GST = 300000
    return SGST+GST

class Car:
    def __init__(self, car_type, price):
        self.car_type = car_type
        self.price = price

    def decor(self, func):
        def wrapper(apply_tax):
            if apply_tax == 'Yes':
                car_tax = tax_price(self.car_type)
                self.price += car_tax
                func()
            else:
                func()
        return wrapper
    @decor
    def car_details(self):
        print("Car Type:", self.car_type)
        print("Car Price: ", self.price)


if __name__ == '__main__':
    car_type = input("Enter type of car: ")
    price = int(input("Enter price of car: "))
    obj = Car(car_type, price)
    tax = {1: "Yes", 2: "No"}
    to_apply = int(input("Select 1 for applying tax and 0 for No:"))
    ans = tax.get(to_apply)
    wrp = obj.car_details()
    wrp(ans)

错误原因

类在加载定义阶段,还没有创建任何实例。@decor语法糖直接调用时,decor作为实例方法需要第一个参数是self,但此时没有实例可以传入,Python会把被装饰的car_details方法当成self参数传递给decor,导致decor缺少了原本必需的func参数,从而抛出参数缺失的错误。

而手动调用时,是先创建Car实例obj,再通过obj.decor获取绑定了实例的方法(self已自动传入),此时调用decor(details)只需要传入func参数,因此可以正常运行。

解决方法

最优方案:实例化后手动绑定装饰器

不在类定义阶段使用@语法糖,而是在__init__方法中,实例创建完成后手动将car_details传入decor,得到装饰后的方法再赋值回属性。这样既保留装饰逻辑,又避开类加载阶段无实例的问题。

修改后的完整代码:

TYPE = {'hybrid': 'Hybrid', 'petrol': 'Petrol', 'deasel': 'Deasel'}

def tax_price(car_type):
    if car_type == 'hybrid':
        SGST = 300000
        GST = 500000
    elif car_type == 'petrol':
        SGST = 200000
        GST = 400000
    elif car_type == 'deasel':
        SGST = 100000
        GST = 300000
    return SGST+GST

class Car:
    def __init__(self, car_type, price):
        self.car_type = car_type
        self.price = price
        # 实例化后手动应用装饰器
        self.car_details = self.decor(self.car_details)

    def decor(self, func):
        def wrapper(apply_tax):
            if apply_tax == 'Yes':
                car_tax = tax_price(self.car_type)
                self.price += car_tax
                func()
            else:
                func()
        return wrapper

    def car_details(self):
        print("Car Type:", self.car_type)
        print("Car Price: ", self.price)


if __name__ == '__main__':
    car_type = input("Enter type of car: ")
    price = int(input("Enter price of car: "))
    obj = Car(car_type, price)
    tax = {1: "Yes", 2: "No"}
    to_apply = int(input("Select 1 for applying tax and 0 for No:"))
    ans = tax.get(to_apply)
    # 直接调用装饰后的方法,传入tax参数
    obj.car_details(ans)

方案说明

  1. 移除car_details上的@decor语法糖,恢复为普通实例方法
  2. 在__init__中,实例初始化完成后,调用self.decor(self.car_details)得到装饰后的方法,重新赋值给self.car_details
  3. 主函数中直接调用obj.car_details(ans)即可,无需手动处理wrapper

这种方式逻辑直观,完全适配原有的装饰器逻辑,同时避免了类定义阶段的实例绑定问题。


内容的提问来源于stack exchange,提问作者Navalkishor Savita

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:21:05