Reputation: 157
I'm trying to redifine the __getattr__ method, in a function.
I've tried this code:
def foo():
print("foo")
def addMethod(obj, func):
setattr(obj, func.__name__, types.MethodType(func, obj))
def __getattr__(obj, name):
print(name)
addMethod(foo, __getattr__)
foo.bar
but I get this error:
Traceback (most recent call last):
File blah blah, line 14, in <module>
foo.bar
AttributeError: 'function' object has no attribute 'bar'
I've inspected the "foo" function and it really has the method bounded to it, but it seems that if you set it dynamically, __getattr__ won't get called. If I do the same thing to a class, if I set the __getattr__ using my "addMethod" function, the instance won't call the __getattr__ too!, so the problem must be the dynamic call!
BUT if I put the __getattr__ in the definition of the class, it will work, obviously.
The question is, how can I put the __getattr__ to the function to make it work? I can't put it from the beginning because it's a function!, I don't know how to do this
Thanks!
Upvotes: 1
Views: 263
Reputation: 69001
Your problem is that Python will only look up __xxx__
magic methods on the class of an object, not the object itself. So even though you are setting __getattr__
on the instance of foo
, it will never be automatically called.
That is also the problem you are having with class foo
:
class foo():
pass
def addMethod(obj, func):
setattr(obj, func.__name__, func)
def __getattr__(obj, name):
print(name)
addMethod(foo, __getattr__)
foo.bar
Here Python is looking up bar
on the class object foo which means . . .
the __getattr__
method you added to foo
is not getting called, instead Python is looking at foo
's metaclass, which is type
.
If you change that last line to
foo().bar
and get an instance of the class of foo, it will work.
Upvotes: 1
Reputation: 129754
Well, you don't. If you want attributes, make a class. If you want instances to be callable, define __call__
for it.
class foo:
def __call__(self):
print("foo")
def __getattr__(self, name):
print(name)
f = foo()
f() # foo
f.bar # bar
Upvotes: 2