当前位置: 代码迷 >> python >> 即使属性存在,getattr()总是调用现有的__getattr __()吗?
  详细解决方案

即使属性存在,getattr()总是调用现有的__getattr __()吗?

热度:84   发布时间:2023-06-16 10:13:53.0

是真的吗

我在下一个代码中遇到困难。 我想稍后在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

从 :

当在常规位置未找到属性时调用该属性(即,它不是实例属性,也不是在自身的类树中找到该属性)。 [...]请注意,如果通过常规机制找到该属性,则不会调用__getattr__()

因此,不,在正常情况下不应调用它。


如果您在为内部方法调用__getattr__遇到麻烦,则可以始终使用object.__getattr__(self, attr_name)来使用python的默认查找。


如果你遇到这样的问题,你可能有一个问题 dunder名字。 如果class属性以得分下的 d ble开头,则python将破坏名称,以便从该类实例以外的任何内容进行访问。 这包括儿童班! 除非您确实需要此功能,否则对“私有”方法/属性使用单个下划线。

没有。

如果存在属性,则不调用__getattr__

当您想要这种行为时,必须使用__getattribute__方法。

在我看来,您的问题是她(正如MiyaGiyagi正确指出的那样),该方法的名称为__m1__m2 (顺便说一句,正确的名称是什么-在一个位置上您将其称为m1在另一个__m1 -不一致)将被系统破坏。 意思是,系统将它们视为_<classname>__<methodname> _MyApi__m1 _<classname>__<methodname>_MyApi__m1 因此,使用“ getattr”时,必须使用变形的名称。