当前位置: 首页 > 后端技术 > Python

Python中几种属性访问的区别

时间:2023-03-25 23:44:36 Python

StartingPython提供了一系列与属性访问相关的特殊方法:__get__、__getattr__、__getattribute__、__getitem__。本文解释了它们的区别和用法。属性访问机制一般情况下,属性访问的默认行为是从对象的字典中获取,获取不到时,会沿着一定的搜索链进行搜索。例如a.x的查找链从a.__dict__['x']开始,然后是type(a).__dict__['x'],然后从type(a)的基类开始查找。如果搜索链无法获取属性,则会抛出AttributeError异常。1.__getattr__方法当对象的属性不存在时调用该方法。如果可以通过正常机制找到对象属性,则不会调用getattr方法。classA:a=1def__getattr__(self,item):print('__getattr__call')returnitem=A()print(t.a)print(t.b)#output1__getattr__callb二、__getattr__方法该方法会被无条件调用。不管属性是否存在。如果类中也定义了getattr,则不会调用getattr__()方法,除非在__getattribute方法中显式调用__getattr__()或抛出AttributeError。A类:a=1def__getattribute__(self,item):print('__getattribute__call')raiseAttributeErrordef__getattr__(self,item):print('__getattr__call')returnitem=A()print(t.a)print(t.b)所以一般来说,__getattribute__()方法为了保留getattr的功能,一般会返回父类的同名方法:def__getattribute__(self,item):returnobject.__getattribute__(self,item)使用基类的方法获取属性防止方法中的无限递归。3.__get__方法这个方法解释起来比较简单,和前面几个关系不大。如果类中定义了__get__()、__set__()或__delete__()中的任何方法。此类的对象称为描述符。类描述(对象):def__get__(self,obj,type=None):print("callget")def__set__(self,obj,value):print("callset")classA(object):x=Descri()a=A()a.__dict__['x']=1#不会调用__get__a.x#如果被查找的属性在描述符对象中,则调用__get__,描述符会覆盖上面的属性访问机制提到的体现在搜索链的不同,文中会因为调用的不同而略有不同:如果调用的是对象实例(标题中的call方法),a.x转换为call:。type(a).__dict__['x'].__get__(a,type(a))如果调用的是类属性,则A.x转换为:A.__dict__['x'].__get__(None,A)other案例见文末文档。4、__getitem__方法的调用也是无条件调用,与getattribute一致。不同的是getitem允许类实例允许[]操作,可以这样理解:__getattribute__适用于所有.经营者;__getitem__适用于所有[]运算符。classA(object):a=1def__getitem__(self,item):print('__getitem__call')returnitem=A()print(t['a'])print(t['b'])如果仅如果想让一个对象能够通过[]获取对象属性,可以很简单:def__getitem(self,item):returnobject.__getattribute__(self,item)总结当这些方法同时出现时,可能打扰您了。在网上看到一个很好的例子,稍微修改了一下:(self,*args,**kwargs)#return"haha"def__getattr__(self,name):print("__getattr__()iscalled")returnname+"fromgetattr"def__get__(self,instance,owner):复制代码print("__get__()iscalled",instance,owner)returnselfdef__getitem__(self,item):print('__getitem__call')returnobject.__getattribute__(self,item)deffoo(self,x):打印(x)类C2(对象):d=C()if__name__=='__main__':c=C()c2=C2()print(c.a)print(c.zzzzzzzz)c2.dprint(c2.d.a)print(c['a'])可以结合输出慢慢理解,这里不涉及继承关系。简而言之,每个以__get为前缀的方法都是一个获取对象内部数据的钩子。名称不同,目的也大不相同。只有在实践中了解它们,才能真正掌握它们的用法。以上就是本次分享的全部内容。想了解更多python知识,请前往公众号:Python编程学习圈,发“J”免费领取,每日干货分享