Reputation: 146
Here is the code
class MyTest:
def __init__(self):
pass
def __getattr__(self, attr):
pass
t = MyTest()
print 'my test object: %r' %t
So print triggers a TypeError: 'NoneType' object is not callable
while i only want to see if object exists.
Granted this code isn't very useful. But i've had a stub class like that in a big code base so i did
if module and module.class and module.class.propery:
# do something with that property
...
and got a Type Error: 'NoneType' object is not callable
but the line doesn't call anything! I guess python is calling some functions implicitly behind the scenes.
Curiously this doesn't happen if the class inherits from Object
What's going on?
Upvotes: 2
Views: 1086
Reputation: 530970
In an old-style class, __getattr__
is used for a greater variety of attribute access, including magic methods. The %
operator is trying to call t.__repr__()
in order to fill in the %r
placeholder, but t.__repr__
is evaluated by t.__getattr__('__repr__')
, which returns None
.
In the if
case, a different magic method is invoked, but the same problem occurs.
>>> class Foo:
... def __getattr__(self, attr):
... print(attr)
...
>>> f = Foo():
>>> if f:
... pass
__nonzero__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
Use a new-style class, __getattr__
is only invoked if an attribute cannot be found via the normal method (checking the __dict__
attribute of the instance or of any of the class's in the instance's MRO).
>>> class Foo(object):
... def __init__(self):
... self.x = 3
... def __getattr__(self, attr):
... print(attr)
...
>>> f = Foo()
>>> if f:
... pass
...
>>> f.x
3
>>> f.y
y
In the if f
case, f
itself doesn't implement __nonzero__
or __len__
, and neither does its parent object
, but in that case, no attribute is used; the fact that f
is, in fact, an object is used. In f.x
, x
is found in the instance's attribute dict, so its value is returned directly. Only y
, which isn't otherwise defined by f
, Foo
, or object
, invokes a call to __getattr__
.
Upvotes: 4
Reputation: 140168
In python 2, with old-style classes, when you try to call __repr__
(when printing) on an object, you have __getattr__
called.
Since you violently stubbed this method, it returns None
and python tries to call None
(because it's expecting a method to be returned)
Try to call object.__getattr__
instead, that'll work:
class MyTest:
def __init__(self):
pass
def __getattr__(self, attr):
print(attr) # so we see why getattr is called
return object.__getattr__(self,attr) # so it doesn't crash (neither it is useful...)
t = MyTest()
print ('my test object: %r' %t)
prints:
__repr__
my test object: <__main__.MyTest instance at 0x00000000031B3808>
this is a specific python 2/old-style object issue. Python 3 or new-style objects don't behave the same
Upvotes: 2