python descriptor 详解.docx

上传人:lao****ou 文档编号:73136 上传时间:2023-01-29 格式:DOCX 页数:9 大小:34.10KB
下载 相关 举报
python descriptor 详解.docx_第1页
第1页 / 共9页
python descriptor 详解.docx_第2页
第2页 / 共9页
python descriptor 详解.docx_第3页
第3页 / 共9页
python descriptor 详解.docx_第4页
第4页 / 共9页
python descriptor 详解.docx_第5页
第5页 / 共9页
亲,该文档总共9页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《python descriptor 详解.docx》由会员分享,可在线阅读,更多相关《python descriptor 详解.docx(9页珍藏版)》请在第一文库网上搜索。

1、pythondescriptor详解.docx目录1. descriptor简介12. descriptor注意事项33. descriptor应用场景54. references81. descriptor简介在python中,如果一个新式类定义了get_,_set_,_delete_方法中的一个或者多个,那么称之为descriptorodescriptor有分为datadescriptor与non-datadescriptor,descriptor通常用来改变默认的属性访问(attributelookup),这部分会在下一遍文章中介绍。注意,descriptor的实例是一定是的属性(cla

2、ssattribute)o这三个特殊的函数签名是这样的:object._get_(self,instance,owner):returnvalueobject._set_(self,instance,value):returnNoneobject._delete_(self,instance):returnNone下面的代码展示了简单的用法:1 #-*-coding:utf-82 classDes(object):3 def_init_(self,init_value):4 self.value=init_value56 def_get_(self,instance,typ):7 print(

3、callget_instance,typ)8 returnself.value910 def_set_(self,instance,value):11 print(call_set_instance,value)12self.value= value1314 def_delete_(self,instance):15 print(call_delete_instance)1617 classWidget(object):18 t=Des1920 defmain():21 w=Widget()22 printtype(w.t)23 w.t=124 printw.t,Widget.t25 delw

4、.t2627 ifname=main*:28 main()运行结果如下:(callget_main_.Widgetobjectat0x02868570,class_main_.Widget)(call_set_main_.Widgetobjectat0x02868570,1)(callget_main_.Widgetobjectat0x02868570,class_main_.Widget)1(call_get_None,)从输出结果可以看到,对于这个三个特殊函数,形参instance是descriptor实例所在的类的实例(w),而形参owner就是这个类(widget)w.t等价于Pro.

5、get(t,w,Widget),而Widget.t等价于Pro.get(t,None,Widget)2. descriptor注意事项需要注意的是,descriptor的实例一定是类的属性,因此使用的时候需要自行区分实例。比如下面这个例子,我们需要保证以下属性不超过一定的阈值。1 classMaxValDes(object):2 def_init_(self,inti_val,max_val):3 self.value=inti_val4 self.max_val=max_val56 defget_(self,instance,typ):7 returnself.value89 def_set

6、_(self,instance,value):10 self.value=min(self.max_val/value)1112 classWidget(object):13 a=MaxValDes(0,10)1415 if_name_=_main_*:16 wO=Widget()17 printinitedw0zwO.a18 wO.a=12319 printaftersetw0,w0.a20 wl=Widget()21 printinitedwl;wl.a代码很简单,我们通过MaxValDes这个descriptor来保证属性的值不超过一定的范围。运行结果如下:initedwO0afters

7、etwO10initedwl10可以看到,对wO.a的赋值符合预期,但是wl.a的值却不是0,而是同wO.a一样。这就是因为,a是类Widget的类属性,Widget的实例并没有,这个属性,可以通过_dict_查看。那么要怎么修改才符合预期呢,看下面的代码:22 classMaxValDes(object):23 def_init_(self,attr,max_val):24 self.attr=attr25 self.max_val=max_val2627 def_get_(self,instance,typ):28 returninstance._diet_self.attr2930 de

8、f_set_(self,instance,value):31 instance.diet_self.attr=min(self.max_val,value)3233 classWidget(object):34 a=MaxValDesCa,10)35 b=MaxValDesCb;12)36 def_init_(self):37 self.a=038 self.b=13940 if_name_=_main_41 wO=Widget()42 printinitedwO,wO.a,wO.b43 wO.a=12344 wO.b=12345 printaftersetw0zw0.a,wO.b4647 w

9、l=Widget()48 printinitedwl,wl.a,wl.b运行结果如下:initedwO01aftersetwO1012initedwO01可以看到,运行结果比较符合预期,wO、wl两个实例互不干扰。上面的代码中有两点需要注意:第一:第7、10行都是通过instance.diet来取值、赋值,而不是调用getattr、setattr,否则会递归调用,死循环。第二:现在类和类的实例都拥有属性,不过wO.a调用的是类属性具体原因参见下一篇文章3. descriptor应用场景其实从上面的例子可以看出,descriptor主要用于控制属性的访问(读、写、删除)。pythondoc里面有

10、写到,property。就是一个datadescriptor实现(可参见这个文档)。python2.2中,大量新式类的实现都基于descriptorTheyarethemechanismbehindproperties,methods,staticmethods,classmethods,andsuper(),TheyareusedthroughoutPythonitselftoimplementthenewstyleclassesintroducedinversion2.2.在实践中,我们有可能需要监控或者限制对属性的访问。比如,对象的一个属性被“莫名其妙”地修改了,但搜索所有文件有找不到可

11、以的地方,那么我们可以通过_setattr_(self,k,v)方法,对于我们关心的k打印出调用栈。另外,也可以用property,示例代码如下:1 classTestProperty(object):2 def_init_(self):3 self,a=1(property6 defa(self):7 returnself._a89 a.setter10 defa(self,v):11 print(outputcallstackhere import functools, time class cached_property(object): A property that is only

12、computed once per instance and thenreplacesitself with an ordinary attribute. Deleting the attribute resets theproperty.def _init_(self, func):functools.update_wrapper(self, func)self.func = func)12 self._a=v1314 if_name_=*_main_15 t=TestPropertyO16 printt.a17 t.a=218 printt.a如果需要禁止对属性赋值,或者对新的值做检查,也

13、很容易修改上面的代码实现既然有了property,那什么时候还需要descriptor呢?property最大的问题在于不能重复使用,即对每个属性都需要property装饰,代码重复冗余。而使用descriptor,把相同的逻辑封装到一个单独的类,使用起来方便多了。笔者之前看bottle.py源码的时候,看到这么一个descriptor使用,部分源代码和测试代码如下:1011 def_get_(self,obj,cis):12 ifobjisNone:returnself13 value=obj._diet_self.func._name_=self.func(obj)14 returnval

14、ue1516 classTestClz(object):17 cached_property18 defcomplex_calc(self):19 printverycomplex_calc20 returnsum(range(100)2122 if_name_=*_main_23 t=TestClz()24 printfirstcall25 plex_calc26 print*secondcall27 plex_calc运行结果如下:firstcallverycomplex_calc4950secondcall4950注意两点:第一,在访问complex_calc的时候并没有使用函数调用(没有括号);第二,第一次调用的时候打印了verycomplex.calc,第二次没有。笔者也是因为这段代码开始学习descriptor,但看懂这段代码还需要了解Python的属性查找顺序,下一篇文章会对此简单介绍。4.references(0)ImplementingDescriptors,python2.7doc(1) DescriptorHowToGuide,https

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 应用文档 > 汇报材料

copyright@ 2008-2022 001doc.com网站版权所有   

经营许可证编号:宁ICP备2022001085号

本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有,必要时第一文库网拥有上传用户文档的转载和下载权。第一文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知第一文库网,我们立即给予删除!



客服