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

Python描述符

时间:2023-03-25 19:43:25 Python

Python描述符注释穿插自己的理解目前Python描述符协议中有4个方法:__get____set____delete____set_name__(Python3.6新增)描述符分为两类:数据描述符、非数据描述符和非数据描述符描述符:只实现了__get__方法数据描述符:实现了__set__或__delete__方法注意:__set_name__:对重分类没有影响(非数据描述符一般不会修改对象,但数据描述符会)Example#ExamplefromCleanCodeinPython#Atravelerwiththecurrentcity在程序运行过程中跟踪用户访问过的所有城市self,owner,name):self._name=namedef__get__(self,instance,owner):如果实例为None:返回self返回实例.__dict__[self._name]def__set__(self,instance,value):self._track_change_in_value_for_instance(instance,value)instance.__dict__[self._name]=valuedef_track_change_in_value_for_instance(self,instance,value):self._set_default(实例)如果self._needs_to_track_change(instance,value):instance.__dict__[self.trace_attribute_name].append(value)def_needs_to_track_change(self,instance,value)->bool:try:current_value=instance.__dict__[self._name]exceptKeyError:returnTrue返回值!=current_valuedef_set_default(self,instance):instance.__dict__.setdefault(self.trace_attribute_name,[])classTraveler:#ownerclasscurrent_city=HistoryTracedAttribute("cities_visited")def__init__(self,name,current_city):self.name=nameself.current_city=current_city描述符类必须是owner类的class属性Newmethod__set_name__signature:object.__set_name__(self,owner,name)self:descriptorclassinstanceowner:ownerclassname:这个变量会得到所有者类的属性名称属性类A:def__get__(self,instance,owner):return55def__set_name__(self,owner,name):print(name)self._name=nameclassB:this_is_name=A()>>>this_is_name非数据描述符__get__signature:object.__g等__(自我,instance,owner=None)self:Descriptorclassinstanceinstance:Ownerclassinstanceowner:Ownerclass此方法应返回计算的属性值或引发AttributeError异常该方法在owner实例的__dict__之后调用,即:classA:def__get__(self,instance,owner):return55classB:value=A()b=B()b.__dict__>>>{}b.value>>>55b.value=99b.__dict__>>>{'value':99}b.value>>>99delb.valueb.value>>>55b.__dict__>>>{}数据描述符__set__signature:object.__set__(self,instance,value)self:dittoinstance:dittovalue:分配数据描述符时传入的值,使得所有描述符方法在所有者实例的__dict__之前被调用,即:classA:def__get__(self,instance,owner):如果实例为None:returnselfreturn55def__set__(self,instance,value):instance.__dict__[self._name]=valuedef__set_name__(self,owner,name):self._name=nameclassB:value=A()b=B()b.value=99b.__dict__>>>{'value':99}b.value>>>55__delete__signature:object.__delete__(self,instance)self:同上instance:同上descriptor实现__set__方法时使用,调用delstatement在owner实例上会调用描述符的__delete__方法,否则会报错:AttributeError:__delete__classA:def__get__(self,instance,owner):如果实例为None:returnselfreturn55def__set__(self,instance,value):instance.__dict__[self._name]=valuedef__set_name__(self,owner,name):self._name=nameclassB:value=A()b=B()b.value=99b.__dict__>>>{'value':99}b.value>>>55delb.value>>>AttributeError:__delete__你不能在描述符方法中使用getattr,setattr只能直接访问__dict__,否则会造成死递归,因为这两个方法内部调用了__get__和__set__。多个owner实例的相同属性引用同一个描述符对象:classA:def__get__(self,instance,owner):ifinstanceisNone:returnselfreturn55def__set__(self,instance,value):instance。__dict__[self._name]=valuedef__set_name__(self,owner,name):self._name=nameclassB:value=A()b1=B()b2=B()id(b1)==id(b2)>>>假id(b1.value)==id(b2.value)>>>True