起步python的提供一系列和属性访问有关的特殊方法:get, getattr, getattribute, getitem 。本文阐述它们的区别和用法。属性的访问机制一般情况下,属性访问的默认行为是从对象的字典中获取,并当获取不到时会沿着一定的查找链进行查找。例如 a.x 的查找链就是,从 a.dict[‘x’] ,然后是 type(a).dict[‘x’] ,再通过 type(a) 的基类开始查找。若查找链都获取不到属性,则抛出 AttributeError 异常。getattr 方法这个方法是当对象的属性不存在是调用。如果通过正常的机制能找到对象属性的话,不会调用 getattr 方法。class A: a = 1 def getattr(self, item): print(’getattr call’) return itemt = A()print(t.a)print(t.b)# output1__getattr__ callb__getattribute__ 方法这个方法会被无条件调用。不管属性存不存在。如果类中还定义了 getattr ,则不会调用 getattr() 方法,除非在 getattribute 方法中显示调用__getattr__() 或者抛出了 AttributeError 。class A: a = 1 def getattribute(self, item): print(’getattribute call’) raise AttributeError def getattr(self, item): print(’getattr call’) return itemt = A()print(t.a)print(t.b)所以一般情况下,为了保留 getattr 的作用,getattribute() 方法中一般返回父类的同名方法:def getattribute(self, item): return object.getattribute(self, item)使用基类的方法来获取属性能避免在方法中出现无限递归的情况。get 方法这个方法比较简单说明,它与前面的关系不大。如果一个类中定义了 get(), set() 或 delete() 中的任何方法。则这个类的对象称为描述符。class Descri(object): def get(self, obj, type=None): print(“call get”) def set(self, obj, value): print(“call set”)class A(object): x = Descri()a = A()a.dict[‘x’] = 1 # 不会调用 __get__a.x # 调用 get__如果查找的属性是在描述符对象中,则这个描述符会覆盖上文说的属性访问机制,体现在查找链的不同,而这个行文也会因为调用的不同而稍有不一样:如果调用是对象实例(题目中的调用方式),a.x 则转换为调用: 。type(a).dict[‘x’].get(a, type(a))如果调用的是类属性, A.x 则转换为:A.dict[‘x’].get(None, A)其他情况见文末参考资料的文档__getitem 方法这个调用也属于无条件调用,这点与 getattribute 一致。区别在于 getitem 让类实例允许 [] 运算,可以这样理解:getattribute 适用于所有 . 运算符;getitem 适用于所有 [] 运算符。class A(object): a = 1 def getitem(self, item): print(’getitem call’) return itemt = A()print(t[‘a’])print(t[‘b’])如果仅仅想要对象能够通过 [] 获取对象属性可以简单的:def __getitem(self, item): return object.getattribute(self, item)总结当这几个方法同时出现可能就会扰乱你了。我在网上看到一份示例还不错,稍微改了下:class C(object): a = ‘abc’ def getattribute(self, *args, **kwargs): print("getattribute() is called") return object.getattribute(self, *args, **kwargs) # return “haha” def getattr(self, name): print("getattr() is called “) return name + " from getattr” def get(self, instance, owner): print("get() is called", instance, owner) return self def getitem(self, item): print(’getitem call’) return object.getattribute(self, item) def foo(self, x): print(x)class C2(object): d = C()if name == ‘main’: c = C() c2 = C2() print(c.a) print(c.zzzzzzzz) c2.d print(c2.d.a) print(c[‘a’])可以结合输出慢慢理解,这里还没涉及继承关系呢。总之,每个以 __ get 为前缀的方法都是获取对象内部数据的钩子,名称不一样,用途也存在较大的差异,只有在实践中理解它们,才能真正掌握它们的用法。参考https://docs.python.org/3/ref…