很久都没写 Flask 代码相关了,想想也真是惭愧,然并卵,这次还是不写 Flask 相关,不服你来打我啊(就这么贱,有本事咬我啊

这次我来写一下 Python 一个很重要的东西,即 Descriptor (描述符)

初识描述符

老规矩, Talk is cheap,Show me the code. 我们先来看看一段代码classPerson(object):

""""""

#----------------------------------------------------------------------

def__init__(self, first_name, last_name):

"""Constructor"""

self.first_name = first_name

self.last_name = last_name

#----------------------------------------------------------------------

@property

deffull_name(self):

"""

Return the full name

"""

return"%s %s"% (self.first_name, self.last_name)

if__name__=="__main__":

person = Person("Mike","Driscoll")

print(person.full_name)

# 'Mike Driscoll'

print(person.first_name)

# 'Mike'

这段代大家肯定很熟悉,恩, property 嘛,谁不知道呢,但是 property 的实现机制大家清楚么?什么不清楚?那还学个毛的 Python

啊。。。开个玩笑,我们看下面一段代码classProperty(object):

"Emulate PyProperty_Type() in Objects/descrobject.c"

def__init__(self, fget=None, fset=None, fdel=None, doc=None):

self.fget = fget

self.fset = fset

self.fdel = fdel

ifdocisNoneandfgetisnotNone:

doc = fget.__doc__

self.__doc__ = doc

def__get__(self, obj, objtype=None):

ifobjisNone:

returnself

ifself.fgetisNone:

raiseAttributeError("unreadable attribute")

returnself.fget(obj)

def__set__(self, obj, value):

ifself.fsetisNone:

raiseAttributeError("can't set attribute")

self.fset(obj, value)

def__delete__(self, obj):

ifself.fdelisNone:

raiseAttributeError("can't delete attribute")

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__)

defdeleter(self, fdel):

returntype(self)(self.fget, self.fset, fdel, self.__doc__)

看起来是不是很复杂,没事,我们来一步步的看。不过这里我们首先给出一个结论: Descriptors 是一种特殊 的对象,这种对象实现了 __get__ ,

__set__ , __delete__ 这三个特殊方法。

详解描述符

说说 Property

在上文,我们给出了 Propery 实现代码,现在让我们来详细说说这个classPerson(object):

""""""

#----------------------------------------------------------------------

def__init__(self, first_name, last_name):

"""Constructor"""

self.first_name = first_name

self.last_name = last_name

#----------------------------------------------------------------------

@Property

deffull_name(self):

"""

Return the full name

"""

return"%s %s"% (self.first_name, self.last_name)

if__name__=="__main__":

person = Person("Mike","Driscoll")

print(person.full_name)

# 'Mike Driscoll'

print(person.first_name)

# 'Mike'

首先,如果你对装饰器不了解的话,你可能要去看看这篇文章,简而言之,在我们正式运行代码之前,我们的解释器就会对我们的代码进行一次扫描,对涉及装饰器的部分进行替换。类装饰器同理。在上文中,这段代码@Property

deffull_name(self):

"""

Return the full name

"""

return"%s %s"% (self.first_name, self.last_name)

会触发这样一个过程,即 full_name=Property(full_name) 。然后在我们后面所实例化对象之后我们调用

person.full_name 这样一个过程其实等价于 person.full_name.__get__(person) 然后进而触发 __get__()

方法里所写的 return self.fget(obj) 即原本上我们所编写的 def full_name 内的执行代码。

这个时候,同志们可以去思考下 getter() , setter() ,以及 deleter()

的具体运行机制了=。=如果还是有问题,欢迎在评论里进行讨论。

关于描述符

还记得之前我们所提到的一个定义么: Descriptors 是一种特殊的对象,这种对象实现了 __get__ , __set__ , __delete__

这三个特殊方法 。然后在 Python 官方文档的说明中,为了体现描述符的重要性,有这样一段话:“They are the mechanism behind

properties, methods, static methods, class methods, and super(). They are used

throughout Python itself to implement the new style classes introduced in

version 2.2. ” 简而言之就是 先有描述符后有天,秒天秒地秒空气

。恩,在新式类中,属性,方法调用,静态方法,类方法等都是基于描述符的特定使用。

OK,你可能想问,为什么描述符是这么重要呢?别急,我们接着看

使用描述符

首先请看下一段代码

classA(object):#注:在 Python 3.x 版本中,对于 new class 的使用不需要显式的指定从 object 类进行继承,如果在

Python 2.X(x>2)的版本中则需要defa(self):

pass

if__name__=="__main__":

a=A()

a.a()

大家都注意到了我们存在着这样一个语句 a.a() ,好的,现在请大家思考下,我们在调用这个方法的时候发生了什么?

OK?想出来了么?没有?好的我们继续

首先我们调用一个属性的时候,不管是成员还是方法,我们都会触发这样一个方法用于调用属性 __getattribute__() ,在我们的

__getattribute__() 方法中,如果我们尝试调用的属性实现了我们的描述符协议,那么会产生这样一个调用过程

type(a).__dict__['a'].__get__(b,type(b))

。好的这里我们又要给出一个结论了:“在这样一个调用过程中,有这样一个优先级顺序,如果我们所尝试调用属性是一个 data descriptors

,那么不管这个属性是否存在我们的实例的 __dict__ 字典中,优先调用我们描述符里的 __get__ 方法,如果我们所尝试调用属性是一个 non data

descriptors ,那么我们优先调用我们实例里的 __dict__ 里的存在的属性,如果不存在,则依照相应原则往上查找我们类,父类中的 __dict__

中所包含的属性,一旦属性存在,则调用 __get__ 方法,如果不存在则调用 __getattr__()

方法”。理解起来有点抽象?没事,我们马上会讲,不过在这里,我们先要解释下 data descriptors 与 non data descriptors

,再来看一个例子。什么是 data descriptors 与 non data descriptors 呢?其实很简单,在描述符中同时实现了 __get__

与 __set__ 协议的描述符是 data descriptors ,如果只实现了 __get__ 协议的则是 non data descriptors

。好了我们现在来看个例子:importmath

classlazyproperty:

def__init__(self, func):

self.func = func

def__get__(self, instance, owner):

ifinstanceisNone:

returnself

else:

value = self.func(instance)

setattr(instance, self.func.__name__, value)

returnvalue

classCircle:

def__init__(self, radius):

self.radius = radius

pass

@lazyproperty

defarea(self):

print("Com")

returnmath.pi * self.radius *2

deftest(self):

pass

if__name__=='__main__':

c=Circle(4)

print(c.area)

好的,让我们仔细来看看这段代码,首先类描述符 @lazyproperty 的替换过程,前面已经说了,我们不在重复。接着,在我们第一次调用 c.area

的时候,我们首先查询实例 c 的 __dict__ 中是否存在着 area 描述符,然后发现在 c 中既不存在描述符,也不存在这样一个属性,接着我们向上查询

Circle 中的 __dict__ ,然后查找到名为 area 的属性,同时这是一个 non data descriptors ,由于我们的实例字典内并不存在

area 属性,那么我们便调用类字典中的 area 的 __get__ 方法,并在 __get__ 方法中通过调用 setattr 方法为实例字典注册属性

area 。紧接着,我们在后续调用 c.area 的时候,我们能在实例字典中找到 area 属性的存在,且类字典中的 area 是一个 non data

descriptors ,于是我们不会触发代码里所实现的 __get__ 方法,而是直接从实例的字典中直接获取属性值。

描述符的使用

描述符的使用面很广,不过其主要的目的在于让我们的调用过程变得可控。因此我们在一些需要对我们调用过程实行精细控制的时候,使用描述符,比如我们之前提到的这个例子classlazyproperty:

def__init__(self, func):

self.func = func

def__get__(self, instance, owner):

ifinstanceisNone:

returnself

else:

value = self.func(instance)

setattr(instance, self.func.__name__, value)

returnvalue

def__set__(self, instance, value=0):

pass

importmath

classCircle:

def__init__(self, radius):

self.radius = radius

pass

@lazyproperty

defarea(self, value=0):

print("Com")

ifvalue ==0andself.radius ==0:

raiseTypeError("Something went wring")

returnmath.pi * value *2ifvalue !=0elsemath.pi * self.radius *2

deftest(self):

pass

利用描述符的特性实现懒加载,再比如,我们可以控制属性赋值的值classProperty(object):

"Emulate PyProperty_Type() in Objects/descrobject.c"

def__init__(self, fget=None, fset=None, fdel=None, doc=None):

self.fget = fget

self.fset = fset

self.fdel = fdel

ifdocisNoneandfgetisnotNone:

doc = fget.__doc__

self.__doc__ = doc

def__get__(self, obj, objtype=None):

ifobjisNone:

returnself

ifself.fgetisNone:

raiseAttributeError("unreadable attribute")

returnself.fget(obj)

def__set__(self, obj, value=None):

ifvalueisNone:

raiseTypeError("You can`t to set value as None")

ifself.fsetisNone:

raiseAttributeError("can't set attribute")

self.fset(obj, value)

def__delete__(self, obj):

ifself.fdelisNone:

raiseAttributeError("can't delete attribute")

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__)

defdeleter(self, fdel):

returntype(self)(self.fget, self.fset, fdel, self.__doc__)

classtest():

def__init__(self, value):

self.value = value

@Property

defValue(self):

returnself.value

@Value.setter

deftest(self, x):

self.value = x

如上面的例子所描述的一样,我们可以判断所传入的值是否有效等等。

以上就是Python 描述符(Descriptor)入门,更多相关文章请关注PHP中文网(www.gxlcms.com)!

本条技术文章来源于互联网,如果无意侵犯您的权益请点击此处反馈版权投诉

本文系统来源:php中文网

python描述_Python描述符(Descriptor)入门相关推荐

  1. python 描述_python描述符

    class Type: def __init__(self, key, expect_type): self.key = key self.expect_type = expect_type def ...

  2. 第十一届蓝桥杯python试题_Python描述 第十一届蓝桥杯省赛第一场 试题 I: 字符串编码...

    试题 I: 字符串编码 时间限制: 1.0s 内存限制: 512.0MB 本题总分 25 分 [问题描述] 小明发明了一种给由全大写字母组成的字符串编码的方法.对于每一个大 写字母 小明将它转换成它在 ...

  3. python 不定积分_python使用sympy不定积分入门及求解

    1.安装 pip3 install sympy 建议使用anaconda,里面有大量的科学包,方便使用! 2.使用 我会根据我的理解和官方教程来进行使用,英语好的可以直接去官网看,防止我可能出现的理解 ...

  4. python书籍_Python书籍大汇总——入门到实战

    学习Python的朋友们越来越多,当当网和京东上面的Python类编程书籍,也从几年前寥寥无几到现在多的不知道选哪本才好了的地步. 无论是自学还是参加培训班跟着老师学习,我们都需要几本实用的Pytho ...

  5. python 响铃_python响铃符不响_python语法注意事项

    ### 语句的缩进 python 与 java 和 c语言 等编程语言最大的不同在于,python语法中不需要使用`大括号{}`,而是使用缩进来表示代码块.这样使得代码更加简洁,也不会因为少写一个大括 ...

  6. 温度转换的python程序_Python通过小实例入门学习---1.0(温度转换)

    1.安装Python 3 下载地址: Welcome to Python.org​www.python.org 2."温度转换"实例:摄氏度--->华氏度 / 华氏度---& ...

  7. python管道_python中管道用法入门,举个例子

    #!coding=utf-8 import multiprocessing def consumer(pipe): output_p , input_p = pipe input_p.close() ...

  8. python如何计算分子描述符_Python——描述符(descriptor)解密

    本文由 极客范 - 慕容老匹夫 翻译自 Chris Beaumont.欢迎加入极客翻译小组,同我们一道翻译与分享.转载请参见文章末尾处的要求. Python中包含了许多内建的语言特性,它们使得代码简洁 ...

  9. python中文件描述符_Python中的描述符

    python中文件描述符 In Python, a class that implements a get, set or delete methods for an object is called ...

  10. python 描述器_python 描述器

    描述符: descriptor 前情要点 调用实例对象属性时,obj.__getattribute__ 方法会首先拦截调用, __getattribute__ 会先从obj中找属性,然后到cls找属性 ...

最新文章

  1. 渗透测试辅助工具--在线版
  2. 鲸鱼优化算法_Java 代码优化细节之比比谁更细
  3. 自动分号插入 ASI
  4. 使用Cloud Application Programming模型开发OData的一个实际例子
  5. [蓝桥杯][2015年第六届真题]生命之树(树形dp)
  6. delphi 调用Msftedit.dll,重写Richedit,支持RTF画表格
  7. excel中怎么把超链接的结果(图片)直接显示出来_把500张产品图片导入Excel里?用这个方法可超速完成,码住...
  8. 泰克吉时利Keithley数据采集器自动计量校准软件NSAT-3070
  9. 433MHz RF Tx-Rx模块如何与Arduino配合使用和接口
  10. Skype for Linux下载地址
  11. leetcode232 用栈实现队列
  12. 2020杭州区块链国际周圆满闭幕,这一份金句集锦不能错过
  13. 图书销售系统 php,php文学小说销售系统
  14. aop:aspectj-autoproxy
  15. firefox正在安装组件,以便播放此页面上的音频或视频
  16. ST-Link资料02_ST-Link固件介绍,及固件命名规则
  17. 北京科技大学 Dog类定义和测试
  18. uniapp onshow如何获得option参数
  19. 网狐框架分析六--整体框架 20150623
  20. 复数四则运算(精简)

热门文章

  1. 羊皮卷的故事-第十七章-羊皮卷之十
  2. 1、CSS 提示工具(Tooltip),2、box-sizing: border-box;的作用,3、实例2 - 图像的透明度 - 悬停效果,4、CSS 图像拼合技术,
  3. 2.UML2 软件建模入门与提高 --- UML入门基础
  4. 11.RabbitMQ实战 --- 提升性能,保障安全
  5. 28.yii2 用户认证
  6. 30.Linux/Unix 系统编程手册(上) -- 线程:线程同步
  7. 25.docker commit
  8. 6.docker images
  9. 9.Linux/Unix 系统编程手册(上) -- 进程凭证
  10. 8. Browser 对象 - History 对象(2)