是真的吗?
我在下一段代码中遇到了困难。我希望稍后在execute()
调用中调用一些方法。但令人惊讶的是,当我调用__getattr__
而不是首先搜索方法__m1和__m2时,python会调用默认方法getattr(self,...)
。
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()
讨论的结果。
我们同意问题出现在两个下划线中,隐藏属性__m1
和__m2
。
答案 0 :(得分:2)
来自docs:
当属性查找未在通常位置找到属性时调用(即,它不是实例属性,也不是在类树中找到自己)。 [...] 请注意,如果通过常规机制找到属性,则不会调用
__getattr__()
。
所以不,在正常情况下不应该调用它。
如果您遇到内部方法调用__getattr__
的问题,可以始终使用object.__getattr__(self, attr_name)
来使用python的默认查找。
如果您遇到此类问题,则可能会遇到name mangling dunder名称的问题。如果一个class属性以 d 两个得分下的开头,那么python将破坏除了该类实例之外的任何访问的名称。这包括儿童班!使用单个下划线表示“私有”方法/属性,除非您确实需要该功能。
答案 1 :(得分:1)
没有
如果存在属性,则不会调用__getattr__
。
如果您需要此类行为,则必须使用方法__getattribute__
。
在我看来,你的问题是(正如MisterMiyagi正确指出的那样),方法命名为__m1
和__m2
(顺便说一句:什么是正确的名字 - 在一个位置你在另一个__m1
中调用它m1 - 这是不一致的)将被系统破坏。这意味着,系统会将其视为_<classname>__<methodname>
或_MyApi__m1
。因此,使用“getattr”时,必须使用损坏的名称。