Reputation: 6754
Is it true?
I have a difficulty in the next code. I want to call some methods later, in the execute()
call. But surprisingly python calls the default-method __getattr__
when I call getattr(self,...)
instead of firstly searching for methods __m1 and __m2.
class MyApi(object):
"Class with API."
def __init__(self):
self.methods = []
class Callable(object):
def __init__(self, obj, name):
self.obj = obj
self.name = name
def __call__(self, *args, **kwargs):
self.obj.methods.append((self.name, args, kwargs,))
def __m1(self, name):
print "m1: name is %s" % name
exit(0)
def __m2(self, *args, **kwargs):
print "m2: args is {} and kwargs is {}".format(args, kwargs)
exit(0)
def execute(self):
for meth in self.methods:
meth_name = '__' + meth[0]
print meth_name
getattr(self, meth_name)(*meth[1], **meth[2]) # it seems to call __getattr__, not existing __m1 and __m2
self.methods = []
def __getattr__(self, name):
return MyApi.Callable(self, name)
api = MyApi()
#import pdb; pdb.set_trace()
api.m1('Serg')
api.m2('John', 'Harrison', **{'key1': 1, 'key2': 2})
api.execute()
The result of a discussion.
We agreed that the problem was in two underscores which hide the attributes __m1
and __m2
.
Upvotes: 2
Views: 2953
Reputation: 50066
From the docs:
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). [...] Note that if the attribute is found through the normal mechanism,
__getattr__()
is not called.
So no, it should not be called under normal circumstances.
If you are having trouble that __getattr__
is called for internal methods, you can always use object.__getattr__(self, attr_name)
to use python's default lookup.
If you do experience such a problem, you might have a problem with name mangling of dunder names. If a class attribute starts with double underscores, python will mangle the name for accesses from anything but instances of the class. This includes child classes! Use single underscores for "private" methods/attributes, unless you really need the functionality.
Upvotes: 4
Reputation: 12728
No.
If an attribute exists, __getattr__
is not called.
When you want such a behavior, you must use the method __getattribute__
.
It seems to me, that your problem her is (as MisterMiyagi correctly pointed out), that the method names __m1
and __m2
(btw: what is the correct name -- in one position you call it m1 in the other __m1
-- that is inconsistent) will be mangled by the system. Meaning, the system sees them as _<classname>__<methodname>
or _MyApi__m1
. So, when using "getattr", you must use the mangled names.
Upvotes: 1