Python类装饰器报错:TypeError: rt()需2参却传1个,如何解决?
问题分析与解决办法
兄弟,这个错误跟你的父类SuperClass半毛钱关系都没有,问题全出在你写的装饰器实现上!咱们一步步拆解:
一、类装饰器的问题根源与修复
你写的类装饰器applyfilter,它的__call__方法没处理好类方法的第一个参数self(也就是T1的实例)。当你用这个装饰器装饰类方法rt后,原来的rt方法就被替换成了applyfilter的实例对象。
举个例子:当你调用t.rt(data)时,Python不会自动把t(T1的实例)传给__call__方法,__call__收到的参数只有(data,)。这时候你调用self.f(*args),就相当于直接调用rt(data),但rt明明需要两个参数(self和data),自然就会报TypeError说参数不够。
修复起来很简单,让__call__接收所有位置参数和关键字参数,原封不动传给原函数,还要记得返回原函数的结果(如果有的话):
class applyfilter(object): def __init__(self, f): self.f = f def __call__(self, *args, **kwargs): # 把所有收到的参数都传给原函数 return self.f(*args, **kwargs)
这样再调用t.rt(data)时,args就会是(t, data),原函数rt就能拿到它需要的两个参数了。
二、函数装饰器的问题排查
你写的函数装饰器其实本身是没问题的,理论上不会出现参数不足的情况。比如你这段代码:
def applyfilter(f): def rt1(*args, **kwargs): print(f.__name__) print(args) return f(*args, **kwargs) return rt1 class T1(SuperClass): @applyfilter def rt(self, data): print("In function rt")
当你创建T1实例调用t.rt("test")时,args会自动带上t这个实例,也就是(t, "test"),传给原函数rt完全符合参数要求。如果你的函数装饰器也报错,大概率是这几个原因:
- 你直接用类调用方法,比如
T1.rt("test"),这种情况需要手动传self参数,不然肯定少一个; - 实际代码里漏写了
return f(*args)?(你提供的代码里是有的,但万一实际写的时候忘了呢); - 你用Python3跑Python2的代码?比如
print f.__name__这种写法在Python3里会报错,但这是语法错误,不是参数错误。
总结一下
- 错误和父类完全无关,就是装饰器对类方法的参数传递处理不到位;
- 类装饰器要确保
__call__能传递所有参数并返回结果; - 函数装饰器本身写法没问题,检查下调用方式是否正确就好。
内容的提问来源于stack exchange,提问作者Neo
相关产品推荐
相关产品推荐

