python对象的魔法方法(一) - __getattr__ vs __getattribute__

了解python的都知道,python对象有很多魔法方法或者叫特殊方法,他们往往以双下划线和单词组成,比如今天的两位 __getattribute____getattr__

这俩方法乍一看,嘿,还挺像,一个单词长一些,一个单词短一些,虽然都是控制属性的访问方法,但是他们之间是有差别的。

__getattribute__

Called unconditionally to implement attribute accesses for instances of the class. If the class also defines getattr(), the latter will not be called unless getattribute() either calls it explicitly or raises an AttributeError. This method should return the (computed) attribute value or raise an AttributeError exception.

意思就是 __getattribute__ 会无条件的实现对类实例的属性控制。在同时存在 __getattr__ 时候, __getattr__ 并不会被访问到,除非你明确的在 __getattribute__ 里面调用了它。

__getattr__

Called when the default attribute access fails with an AttributeError (either getattribute() raises an AttributeError because name is not an instance attribute or an attribute in the class tree for self; or get() of a name property raises AttributeError). This method should either return the (computed) attribute value or raise an AttributeError exception.

__getattr__ 呢则是在默认属性失败的情况下,会去调用它,看看它是否有实现对属性的访问权。在这里要注意一点就是: Note that if the attribute is found through the normal mechanism, __getattr__() is not called. - 在常规机制下能访问到的属性,getattr() 是不会被调用的。

具体看以下例子:

class MyClass(object):

    def __init__(self):
        self.name = "John Doe"

    def __getattribute__(self, name):
    	print(f"__getattribute__: {name}")
        if name == "age":
            return 30
        else:
            return object.__getattribute__(self, name)

    def __getattr__(self, name):
        print("The attribute {} is not defined".format(name))


instance = MyClass()

print(instance.name)  # John Doe
print(instance.age)  # 30
print(instance.address)  # The attribute address is not defined

"""
Output:
__getattribute__: name
John Doe

__getattribute__: age
30

__getattribute__: address
The attribute address is not defined
"""

从这个例子可以看到:

  1. 属性的访问,都会直接走 __getattribute__ 方法
  2. 常规属性的访问,并不会直接走 __getattr__ 方法
  3. 当对象访问不存在的属性名字时候,__getattr__ 会被调用;
  4. 【可以自己将 __getattr__ 注释掉】如果没有该魔法方法,则会报错 AttributeError: 'MyClass' object has no attribute 'address'

你可能感兴趣的:(python,linux,开发语言)