Python中的类与对象之描述符_第1页
Python中的类与对象之描述符_第2页
Python中的类与对象之描述符_第3页
Python中的类与对象之描述符_第4页
Python中的类与对象之描述符_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Python中的类与对象之描述符描述符(descriptors)是python语言中一个深奥但却重要的一部分。它们广泛应用于python语言的内核,熟练掌握描述符将会为python程序员的工具箱添加一个额外的技巧。下面是小编为大家整理的Python中的类与对象之描述符,欢迎大家借鉴与参考,希望对大家有所帮助。1、假设一个程序中,我们需要对一个对象属性执行严格的类型检查。然而,Python是一种动态语言,所以并不支持类型检查,但是这并不妨碍我们实现自己版本,且较为初级的类型检查。对象属性类型检查的传统方法可能采用下面的方式:definit(self,name,age):ifisinstance(str,name):=nameelse:raiseTypeError("Mustbeastring")ifisinstance(int,age):self.age=ageelse:raiseTypeError("Mustbeanint")上面是执行这种类型检查的一种方法,但是参数数量增加时它将变得比较繁琐。另外,在赋值之前,我们可以创建一个在init中调用的type_check(type,val)函数,但是当我们想在其他地方设置属性值时,该如何简单地实现这种检查呢。我想到的一个快速解决方案是Java中的getters和setters,但是这并不符合Python风格,并且比较麻烦。2、假设在一个程序中,我们想创建一些在运行时立刻初始化然后变成只读的属性。有人也能想到利用Python中的特殊方法来实现,但这种实现方法仍旧是笨拙和繁琐的。3、最后,设想一个程序中,我们希望以某种方式自定义对象属性的访问。例如需要记录这种属性的访问。同样的,还是可以想到一个解决方法,即使这种解决方案可能比较笨重并且不可复用。上述问题因都与属性引用相关而全部联系在了一起。下面,我们将尝试自定义属性的访问方法。Python描述符针对上面所列的问题,描述符提供了优雅、简洁、健壮和可重用的解决方案。简而言之,一个描述符就是一个对象,该对象代表了一个属性的值。这就意味着如果一个账户对象有一个属性“name”,那么描述符就是另一个能够用来代表属性“name”持有值的对象。描述符协议中“定义了get”、“set”或””这些特殊方法,描述符是实现其中一个或多个方法的对象。这些方法中每一种方法的签名如下所示:pythondescr.get(self,obj,type=None)->value。descr.set(self,obj,value)-->Nonedescr.(self,obj)-->No实现get方法的对象是非数据描述符,意味着在初始化之后它们只能被读取。而同时实现get和set的对象是数据描述符,意味着这种属性是可写的。为了更好地理解描述符,我们给出针对上述问题基于描述符的解决方法。使用Python描述符实现对象属性的类型检查将是一个非常简单的任务。装饰器实现这种类型检查的代码如下所示:classTypedProperty(object):definit(self,name,type,default=None):="_"+nameself.type=typeself.default=defaultifdefaultelsetype()defget(self,instance,cls):returngetattr(instance,,self.default)def___set__(self,instance,value):ifnotisinstance(value,self.type):raiseTypeError("Mustbea%s"%self.type)setattr(instance,,value)raiseAttributeError("Cantattribute")classFoo(object):name=TypedProperty("name",str)num=TypedProperty("num",int,42)>>="obi">>printacct.num>>print#tryingtoassignastringtonumberfails在这个例子中,我们实现了一个描述符TypedProperty,并且这个描述符类会对它所代表的类的任何属性执行类型检查。注意到这一点很重要,即描述符只能在类级别进行合法定义,而不能在实例级别定义。例如,在上面例子中的init方法里。当访问类Foo实例的任何属性时,描述符会调用它的get方法。需要注意的是,get方法的第一个参数是描述符代表的属性被引用的源对象。当属性被分配时,描述符会调用它的set方法。为了理解为什么可以使用描述符代表对象属性,我们需要理解Python中属性引用解析的执行方式。对于对象来说,属性解析机制在object.__getattribute()中。该方法将b.x转换成type(b).__dict[x].__get(b,type(b))。然后,解析机制使用优先级链搜索属性,在优先级链中,类字典中发现的数据描述符的优先级高于实例变量,实例变量优先级高于非数据描述符,如果提供了getattr(),优先级链会为getattr()分配最低优先级。对于一个给定的对象类,可以通过自定义getattribute方法来重写优先级链。深刻理解优先级链之后,就很容易想出针对前面提出的第二个和第三个问题的优雅解决方案了。那就是,利用描述符实现一个只读属性将变成实现数据描述符这个简单的情况了,即不带set方法的描述符。尽管在本例中不重要,定义访问方式的问题只需要在get和set方法中增加所需的功能即可。类属性每次我们想使用描述符的时候都不得不定义描述符类,这样看起来非常繁琐。Python特性提供了一种简洁的方式用来向属性增加数据描述符。一个属性签名如下所示:property(fget=None,fset=None,fdel=None,doc=None)->propertyattributefget、fset和fdel分别是类的getter、setter和r方法。我们通过下面的一个示例来说明如何创建属性:classAccout(object):self._acct_num=Nonedefget_acct_num(self):returnself._acct_numdefset_acct_num(self,value):self._acct_num=valuedefdel_acct_num(self):delself._acct_numacct_num=property(get_acct_num,set_acct_num,del_acct_num,"Accountnumberproperty.")如果acct是Account的一个实例,acct.acct_num将会调用getter,acct.acct_num=value将调用setter,delacct_num.acct_num将调用r。在Python中,属性对象和功能可以像《描述符指南》中说明的那样使用描述符协议来实现,如下所示:classProperty(object):"EmulatePyProperty_Type()inObjects/descrobject.c"definit(self,fget=None,fset=None,fdel=None,doc=None):self.fget=fgetself.fset=fsetself.fdel=fdeldoc=fget.docself.doc=docdefget(self,obj,objtype=None):returnselfraiseAttributeError("unreadableattribute")returnself.fget(obj)defset(self,obj,value):raiseAttributeError("cantsetattribute")self.fset(obj,value)def(self,obj):ifself.fdelisNone:raiseAttributeError("cantattribute")self.fdel(obj)defgetter(self,fget):returntype(self)(fget,self.fset,self.fdel,self.__doc)defsetter(self,fset):returntype(self)(self.fget,fset,self.fdel,self.__doc)defr(self,fdel):returntype(self)(self.fget,self.fset,fdel,self.__doc)Python也提供了@property装饰器,可以用它来创建只读属性。一个属性对象拥有getter、setter和r装饰器方法,可以使用它们通过对应的被装饰函数的accessor函数创建属性的拷贝。下面的例子最好地解释了这一点:classC(object):@property#thexproperty.thedecoratorcreatesaread-onlypropertydefx(self):returnself._x@x.setter#thexpropertysettermakesthepropertywriteabledefx(self,value):self._x=value@x.rdefx(self):delself._x如果我们想让属性只读,那么我们可以去掉setter方法。在Python语言中,描述符有着广泛的应用。Python函数、类方法、静态方法都是非数据描述符的例子。针对列举的Python对象是如何使用描述符实现的问题,《描述符指南》给出了一个基本的描述。这些方法有

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论