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