Python类方法self参数传递问题:调用实例方法报错求助
我正在编写通用函数,希望调用带参数的实例方法并在方法内访问self。编写了Test类代码如下:
class Test: aggregation = [{'function_name': 'functionA', 'parameters': {'weight': 10}},..] generic_parameters = {'_id': 1234} # all things generic to the user version = 0.7 def functionA(self, _id=None, weight=1.0): print(self.version) pass def functionB(..): pass def functionC(..): pass function_dict = {'functionA': functionA, 'functionB': functionB, 'functionC': functionC} # Push all functions into here def __init__(self, _id=None): self._id = _id def s(self): for s_score in self.aggregation: function_name = sub_score['function_name'] parameters = sub_score['parameters'] sub_parameters = self.generic_parameters sub_parameters.update(parameters) op = self.function_dict[function_name](**sub_parameters) print(op)
运行test = Test(); test.s()时,报错:
TypeError: functionA() missing 1 required positional argument: 'self'
报错行是op = self.function_dict[function_name](**sub_parameters)。
我尝试改用getattr,将调用代码改为op = getattr(self, function_name)(**parameters),但此时functionA中出现错误:
AttributeError: 'Test' object has no attribute '_id'
请问getattr(self, function_name)(**parameters)是否未传入self?若如此,该如何正确实现?
第一个错误:TypeError(缺少self参数)
原因
function_dict是类属性,存储的是未绑定到实例的原始类方法。直接调用时,Python不会自动将当前实例self作为第一个参数传入,因此触发缺少self的错误。
解决方法
有两种可行方案:
实例初始化时绑定方法(推荐):
将function_dict的初始化移到__init__方法中,存储绑定到当前实例的方法,调用时会自动传入self:def __init__(self, _id=None): self._id = _id self.function_dict = { 'functionA': self.functionA, 'functionB': self.functionB, 'functionC': self.functionC }原调用代码
op = self.function_dict[function_name](**sub_parameters)即可正常运行。手动传入self参数:
调用时显式将self作为第一个参数传入,这种写法不够符合Python面向对象规范,仅作备选:op = self.function_dict[function_name](self, **sub_parameters)
第二个错误:AttributeError(_id属性不存在)
原因
getattr(self, function_name)(**parameters)已经正确传入了self,报错的核心原因有两种可能:
- 变量名笔误:
s方法中循环变量是s_score,但后续使用了sub_score['function_name'],这会先触发NameError,修复后才会暴露_id相关问题; - 实例属性未正确赋值:检查
__init__方法的缩进,确保self._id = _id在__init__代码块内;如果实例化时未传入_id,self._id的值是None,但不会触发AttributeError——除非__init__里根本没赋值self._id; - 参数与实例属性混淆:如果
functionA中需要使用传入的_id参数,而非实例属性self._id,应直接写_id而非self._id;反之,若需要实例属性,确保__init__正确赋值。
另外,原代码中sub_parameters = self.generic_parameters会直接引用类属性,修改sub_parameters会改变整个类的generic_parameters值,建议改为创建新字典:
sub_parameters = self.generic_parameters.copy() sub_parameters.update(parameters)
最终修正后的示例代码
class Test: aggregation = [{'function_name': 'functionA', 'parameters': {'weight': 10}}] generic_parameters = {'_id': 1234} version = 0.7 def functionA(self, _id=None, weight=1.0): print(f"self.version: {self.version}") print(f"self._id: {self._id}") print(f"parameter _id: {_id}") return "functionA executed" def functionB(self): pass def functionC(self): pass def __init__(self, _id=None): self._id = _id self.function_dict = { 'functionA': self.functionA, 'functionB': self.functionB, 'functionC': self.functionC } def s(self): for s_score in self.aggregation: function_name = s_score['function_name'] parameters = s_score['parameters'] # 创建新字典避免修改类属性 sub_parameters = self.generic_parameters.copy() sub_parameters.update(parameters) # 使用绑定后的方法调用 op = self.function_dict[function_name](**sub_parameters) print(op) # 测试 test = Test(_id=5678) test.s()
运行输出:
self.version: 0.7 self._id: 5678 parameter _id: 1234 functionA executed
内容的提问来源于stack exchange,提问作者DBA_player

