python descriptor 官方文档指引[翻译]

来源:互联网 发布:mac windows虚拟机 编辑:程序博客网 时间:2024/06/05 16:28

翻译自官方文档描述符指引

摘要

定义描述符,概述描述符的协议,并且展示描述符如何被调用。检查自定义描述符和几个内置的python描述符(包括函数、属性,静态方法和类方法)。通过一段python示例程序去展示描述符是怎么执行的。

学习描述符不仅提供了接触更多工具的机会,也会对python运行机制和设计优雅的代码有更深入的理解。


定义和介绍

一般来说,一个描述符是一个绑定的对象属性,它能够被描述符里的方法覆盖。这样的方法有__get__(), __set__() 和__delete__()。如果有一个对象定义了这些方法,那就可以称作一个描述符。

访问属性的默认行为是从一个对象的字典中get,set或delete这个属性。例如,a.x有一个以a.__dict__['x']开头的查找链,然后是type(a).__dict__['x'],最后是除了元类的type(a) 的基类。如果查找的值是描述符方法定义的对象,那么python就会重写默认的行为,并且调用描述符的方法。在优先级链中发生的位置取决于定义了哪些描述符方法。注意,描述符仅仅被调用用于新式对象或类(类继承自object或者type)。

描述符是一个强大的通用协议。它们是属性,方法,静态方法,类方法和super()背后的机制。它们被用于整个Python本身以实现在2.2版本中引入的新风格类。描述符简化了底层C代码,为日常Python程序提供了一套灵活的新工具。


描述符协议

descr.__get__(self, obj, type=None) --> valuedescr.__set__(self, obj, value) --> Nonedescr.__delete__(self, obj) --> None

以上就是所有的描述符协议,一个对象定义了任何以上的方法都可以视为描述符,并且可以在查找属性时重写默认的行为。

如果一个对象定义了__get()__和__set__(),这个对象就可视为一个数据描述符。如果只定义了__get__()就被称为非数据描述符。

数据和非数据描述符的区别在于如何覆盖对于实例的字典中的条目计算。如果实例的字典具有与数据描述符相同名称的条目,则数据描述符优先。如果实例的字典具有与非数据描述符相同名称的条目,则字典条目优先。

实现一个只读的数据描述符,需要用到__get__()和__set__(),当这个描述符被调用的时候__set__()抛出一个AttributeError,用一个抛出异常的占位去定义__set__()方法足以使之成为数据描述符。


获取描述符

一个描述符可以被方法名直接调用,例如,d.__get__(obj).

另外一种更常见的是在访问属性的时候自动调用描述符。例如,obj.d是在obj的字典中查询d。如果d定义了__get__()方法,则根据下面列出的优先级规则调用d .__get__(obj)。

调用的细节取决于obj是一个对象还是一个类。无论哪种方式,描述符只适用于新样式对象和类。新式类是他的子类继承于object。

对于对象,这构造是在object.__getattribute__()中转换b.x为type(b).__dict__['x'].__get__(b, type(b))。该实现通过一个数据描述符>实例变量>非数据描述符的优先链,并且如果__getattr__()存在,就赋予它最低优先级,完整的c语言实现可以在object.c中找到。

对于类,这构造是在type.__getattribute__()中转换B.x为B.__dict__['x'].__get__(b, type(b))。用python实现如下:

def __getattribute__(self, key):    "Emulate type_getattro() in Objects/typeobject.c"    v = object.__getattribute__(self, key)    if hasattr(v, '__get__'):        return v.__get__(None, self)    return v
(占坑更新。。。)


0 0
原创粉丝点击