Using __getattr__ causes TypeError : ‘str’ object is not callable – Python 2. 7
I
tried to define a simple class and instance in Python 2.7, but I’m having trouble with __getattr__. The following minimal working example:
class MyClass:
def __init__(self,value):
self.a = value
def __getattr__(self,name):
return 'hello'
class MyOtherClass:
def __init__(self,value):
self.a = value
MyInstance = MyClass(6)
MyOtherInstance = MyOtherClass(6)
Now, if I type dir(MyInstance),
I get:
TypeError: 'str' object is not callable
But if I type dir(MyOtherInstance)
I get:
['__doc__', '__init__', '__module__', 'a']
Similarly, if I type MyInstance
, I get:
TypeError: 'str' object is not callable
But if I type MyOtherInstance
I get:
<__main__. MyOtherClass instance at 0x0000000003458648>
MyOtherInstance
behaved as I expected. Why don’t I get this behavior when I use MyInstance
?
Solution
The problem is that MyClass
is a legacy class (i.e., it doesn’t explicitly inherit from object
or another modern class), which means that __getattr__ is used for magic methods and does not trigger a call to __getattr__
in a modern class.
To see this, change your class to
class MyClass:
def __init__(self,value):
self.a = value
def __getattr__(self,name):
print("Looking up %s" % (name,))
return 'hello'
The simple use of MyInstance
triggers a call to MyInstance.__repr__
, but __repr__ evaluates to the string ‘hello’ instead of the class's
__repr__
method.
>>> MyInstance
Looking up __repr__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
Similarly, dir(MyInstance)
triggers a call to MyClass.__dir__
, while __dir__
, which is also the string ‘hello'
, is not an appropriate method.
>>> dir(MyInstance)
Looking up __dir__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
MyOtherClass
doesn’t have the same problem because you don’t overwrite __getattr__
.
Inheriting from object
solves this problem; Look for magic methods individually before going back to __getattr__
.
class MyClass(object):