简体   繁体   English

python中的__getattr__方法

[英]__getattr__ method in python

i meet this code today, and it seems confusing 我今天遇到这个代码,看起来很混乱

class ClassOne:
    def __init__(self,some_object):
        self.not_important_attribute=some_object   
class ClassTwo:
    def __init__(self,some_object):
        self.tmp=ClassOne(some_object)
    def __getattr__(self,attr):
        return getattr(self.tmp,attr)
a=ClassTwo('not_important_string')
print(getattr(a,'undefined_attribute',3))

When we use getattr at the last line we trigger the __getattr__ method in the SubClass , then delegate to the getattr(self.tmp,attr) function which will raise an exception if the attribute is undefined and no default value was given. 当我们在最后一行使用getattr时,我们在SubClass触发__getattr__方法,然后委托给getattr(self.tmp,attr)函数,如果该属性未定义且没有给出默认值,则会引发异常。 But how the value 3 at the last line still go through all the process, and eventually return to getattr(a,'undefined_attribute',3) function ?. 但是最后一行的值3如何仍然经历所有过程,并最终返回到getattr(a,'undefined_attribute',3)函数? Because we didn't have a slot for the default value when we delegate getattr(self.tmp,attr) , how is that possible ? 因为当我们委托getattr(self.tmp,attr)时我们没有用于默认值的插槽,这怎么可能?

In your case 在你的情况下

getattr(self.tmp,attr)

raises AttributeError and if getattr has third argument(default value) then it return default value instead of raising AttributeError 引发AttributeError,如果getattr有第三个参数(默认值),则返回默认值而不是引发AttributeError

Step by step why 3 value is shown: 一步一步为什么显示3值:

the super class has has an atribute not_important_attribute and it is set when the constructor is called 超类有一个属性not_important_attribute ,它在调用构造函数时设置

class ClassOne:
    def __init__(self,some_object):
        self.not_important_attribute=some_object   

Here, in the ClassTwo contructor, you create an instance of ClassOne and save it into tmp variable. 这里,在ClassTwo构造ClassTwo ,您创建一个ClassOne实例并将其保存到tmp变量中。 Meaning that when you overrides __getattr__ you will be asking for the value of attribute of ClassOne 这意味着当你覆盖__getattr__你将要求ClassOne的属性值

print(getattr(a,'not_important_attribute',3))
not_important_string # founds the method
print(getattr(a,'any',3))
3 #doesn't found method, returns default

That is the same of directly do: 这是直接做的:

b = ClassOne("not_important_string")
print(getattr(b,'not_important_attribute',3))
not_important_string # founds the method
print(getattr(b,'any',3))
3 # doesn't found method, returns default  

When calling getattr(a,'undefined_attribute',3) you are calling the standard python getattr function and pass it a default value. 当调用getattr(a,'undefined_attribute',3)您调用标准的python getattr函数并将其传递给默认值。 This actually wraps your custom getattr in ClassTwo. 这实际上将您的自定义getattr包装在ClassTwo中。 We can see that by modifying getattr al little bit. 我们可以看到通过稍微修改getattr

   def __getattr__(self, attr, *args, **kwargs):
        print(args)  # -> empty
        print(kwargs)  # -> empty
        return getattr(self.tmp, attr)

You can actually go around that wrapping and call getattr from ClassTwo directly, by using print(a.__getattr__('undefined_attribute', 3)) . 实际上,您可以使用print(a.__getattr__('undefined_attribute', 3))绕过包装并直接从ClassTwo调用getattr This method would raise an Exception. 此方法会引发异常。

So essentially getattr(a,'undefined_attribute',3) is the standard python method that internally calls the custom getattr from ClassTwo. 所以基本上getattr(a,'undefined_attribute',3)是内部从ClassTwo调用自定义getattr的标准python方法。

class ClassTwo:
...
    def __getattr__(self,attr):
        return getattr(self.tmp,attr)

getattr(a,'undefined_attribute',3) method is a wrapper to call __getattribute__ and if __getattribute__ fails, it will call __getattr__ . getattr(a,'undefined_attribute',3)方法是一个调用__getattribute__的包装器,如果__getattribute__失败,它将调用__getattr__ It is implemented with handling of exception AttributeError . 它通过处理异常AttributeError来实现。 In your case, getattr(a,'undefined_attribute',3) calls ClassTwo.__getattr__ above. 在你的情况下, getattr(a,'undefined_attribute',3)调用ClassTwo.__getattr__

It seems you think when it reaches return getattr(self.tmp,attr) , it will throw errors or return some kind of errors and break and stop at that point complete. 看来你认为当它到达return getattr(self.tmp,attr) ,它会抛出错误或返回某种错误并在那一点完成破解和停止。 However, in python, program will pass exception up the call stack. 但是,在python中,程序会将异常传递给调用堆栈。 Along the upstream of the call stack, if that exception gets handle, it will exit/complete normally. 沿着调用堆栈的上游,如果该异常得到处理,它将正常退出/完成。 In this case, AttributeError get passed back along the call stack to getattr(a,'undefined_attribute',3) . 在这种情况下, AttributeError会沿着调用堆栈传递回getattr(a,'undefined_attribute',3) this getattr has default value for AttributeError so it returns 3 and exits normally. getattr具有AttributeError默认值,因此它返回3并正常退出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM