Python2.7使用__getattr__触发TypeError: 'str'对象不可调用问题
问题原因与解决方案
这个问题的根源在于Python 2里旧式类(没有继承object的类)和新式类的属性查找机制差异,尤其是对特殊方法/属性的处理。
为什么MyInstance会报错?
你的MyClass是Python 2中的旧式类(没有继承object),而__getattr__在旧式类中的行为和新式类完全不同:
- 对于旧式类,当你访问任何实例上不存在的属性(包括像
__dir__、__repr__这类特殊方法)时,都会触发__getattr__。 - 当你调用
dir(MyInstance)时,Python会尝试访问实例的__dir__方法来获取属性列表。但旧式类实例本身没有__dir__方法,所以这个属性查找会失败,进而触发你的__getattr__,返回字符串'hello'。接下来dir()会尝试调用这个返回值(因为它期望__dir__是一个可调用方法),但字符串是不能被调用的,于是就抛出了TypeError: 'str' object is not callable。 - 同样,当你直接输入
MyInstance时,Python会尝试调用实例的__repr__方法来生成字符串表示。在旧式类的属性查找逻辑下,这个过程会触发__getattr__,返回的字符串会被当作方法去调用,同样导致报错。
而MyOtherClass虽然也是旧式类,但它没有定义__getattr__,所以当dir()或者打印实例时,Python会使用默认的逻辑(比如从类层面获取__repr__、用默认方式收集属性),所以行为符合预期。
解决方法
方法1:改用新式类(推荐)
把MyClass改成继承object的新式类,这样特殊方法的查找会直接在类层面进行,不会触发实例的__getattr__:
class MyClass(object): # 继承object变为新式类 def __init__(self, value): self.a = value def __getattr__(self, name): return 'hello'
修改后:
dir(MyInstance)会正常返回属性列表,使用从object继承的__dir__方法,不会触发你的__getattr__。- 直接输入
MyInstance会返回类似<__main__.MyClass object at 0x0000000003458648>的正常表示。
方法2:在__getattr__中过滤特殊属性(兼容旧式类)
如果必须保留旧式类,可以在__getattr__中跳过对特殊属性的处理,让Python使用默认逻辑:
class MyClass: def __init__(self, value): self.a = value def __getattr__(self, name): # 跳过以双下划线包裹的特殊属性/方法 if name.startswith('__') and name.endswith('__'): raise AttributeError(name) return 'hello'
这样,当访问__dir__、__repr__这类特殊属性时,会抛出AttributeError,Python会继续使用默认的处理逻辑,避免触发错误。
内容的提问来源于stack exchange,提问作者FinrodFelagund
相关产品推荐
相关产品推荐

