混淆Setter与Getter?调用Setter时为何触发‘str’ object is not callable错误?
我完全懂你的困扰——明明已经抛弃了Java风格的get/set函数,改用Python更优雅的property来做属性控制,还特意用双下划线把内部属性设为私有,结果还是碰到了这个'str' object is not callable错误,而且常见的“属性与方法同名”的坑你已经避开了,这就更让人挠头对吧?别慌,咱们来拆解几个你可能没注意到的细节:
可能的原因1:不小心覆盖了property方法
虽然你用了双下划线的私有属性,但如果在__init__或者其他方法里,错误地给和property同名的实例属性赋值,就会把property装饰的方法给覆盖成字符串。比如下面这个错误示例:
class Person: def __init__(self): self.__name = "Alice" self.name = self.__name # 这里踩坑了!把实例的name属性设为字符串,覆盖了@property的方法 @property def name(self): return self.__name
这时候你实例化后,p.name直接是字符串"Alice",如果不小心写成p.name()(把属性当成方法调用),就会触发'str' object is not callable错误。
解决办法:
彻底避免给和property同名的实例属性直接赋值,所有内部状态都存在双下划线的私有属性里,比如self.__name,让property方法完全接管外部的属性访问。
可能的原因2:Setter方法里的赋值错误
如果你的property定义了setter,但在setter里错误地把值赋给property本身而不是私有属性,也会引发问题(甚至可能间接导致属性被覆盖)。比如:
class Person: def __init__(self): self.__age = 18 @property def age(self): return self.__age @age.setter def age(self, value): self.age = value # 这里错了!应该是self.__age = value
这段代码里,self.age = value会无限触发setter方法,最终可能导致栈溢出,但如果中途某个环节把age变成了字符串,后续访问也会触发相同的错误。
解决办法:
在setter方法里,一定要把值赋值给双下划线的私有属性,比如self.__age = value,确保修改的是内部存储,而不是触发property的访问逻辑。
可能的原因3:误把属性当成方法调用
有时候只是手滑——property是用来像访问普通属性一样使用的,不需要加括号。如果你写成了p.name()而不是p.name,那就是在尝试调用一个字符串,自然会报错。
解决办法:
去掉多余的括号,直接用实例.属性名的方式访问或赋值。
正确的property使用示例
最后给你一个标准的正确写法,参考这个来调整你的代码:
class Person: def __init__(self): # 内部用双下划线私有属性存储 self.__name = "Alice" self.__age = 18 @property def name(self): # Getter:返回私有属性 return self.__name @name.setter def name(self, value): # Setter:可以加验证逻辑 if not isinstance(value, str): raise ValueError("Name must be a string") self.__name = value # 赋值给私有属性 @property def age(self): # 只读属性,没有setter return self.__age
使用的时候:
p = Person() print(p.name) # 输出 "Alice" p.name = "Bob" print(p.name) # 输出 "Bob" print(p.age) # 输出 18 # p.age = 20 # 会报错,因为age是只读属性
内容的提问来源于stack exchange,提问作者igor Smirnov

