返回介绍

描述符

发布于 2024-01-29 22:24:14 字数 2557 浏览 0 评论 0 收藏 0

描述符提供了拦截属性访问的一种替代方法;它们与前面小节所讨论的特性有很大的关系。实际上,特性是描述符的一种——从技术上讲,property内置函数只是创建一个特定类型的描述符的一种简化方式,而这种描述符在属性访问时运行方法函数。

从功能上讲,描述符协议允许我们把一个特定属性的get和set操作指向我们提供的一个单独类对象的方法:它们提供了一种方式来插入在访问属性的时候自动运行的代码,并且它们允许我们拦截属性删除并且为属性提供文档(如果愿意的话)。

描述符作为独立的类创建,并且它们就像方法函数一样分配给类属性。和任何其他的类属性一样,它们可以通过子类和实例继承。通过为描述符自身提供一个self,以及提供客户类的实例,都可以提供访问拦截方法。因此,它们可以自己保留和使用状态信息,以及主体实例的状态信息。例如,一个描述符可能调用客户类上可用的方法,以及它所定义的特定于描述符的方法。

和特性一样,描述符也管理一个单个的、特定的属性。尽管它不能广泛地捕获所有的属性访问,但它提供了对获取和赋值访问的控制,并且允许我们自由地把简单的数据修改为计算值从而改变一个属性,而不会影响已有的代码。特性实际上只是创建一种特定描述符的方便方法,并且,正如我们所见到的,它们可以直接作为描述符编写。

然而,特性的应用领域相对狭窄,描述符提供了一种更为通用的解决方案。例如,由于它们编码为常规类,所以描述符拥有自己的状态,可能参与描述符继承层级,可以使用复合来聚合对象,并且为编写内部方法和属性文档字符串提供一种自然的结构。

基础知识

正如前面所提到的,描述符作为单独的类编写,并且针对想要拦截的属性访问操作提供特定命名的访问器方法——当以相应的方式访问分配给描述符类实例的属性时,描述符类中的获取、设置和删除等方法自动运行:

带有任何这些方法的类都可以看作是描述符,并且当它们的一个实例分配给另一个类的属性的时候,它们的这些方法是特殊的——当访问属性的时候,会自动调用它们。如果这些方法中的任何一个空缺,通常意味着不支持相应类型的访问。然而,和特性不同,省略一个__set__意味着允许这个名字在一个实例中重新定义,因此,隐藏了描述符——要使得一个属性是只读的,我们必须定义__set__来捕获赋值并引发一个异常。

描述符方法参数

在进行任何真正的编程之前,先来回顾一些基础知识。前面小节介绍的所有3种描述符方法,都传递了描述符类实例(self)以及描述符实例所附加的客户类的实例(instance)。

__get__访问方法还额外地接收一个owner参数,指定了描述符实例要附加到的类。其instance参数要么是访问的属性所属的实例(用于instance.attr),要么当所访问的属性直接属于类的时候是None(用于class.attr)。前者通常针对实例访问计算一个值;如果描述符对象访问是受支持的,后者通常返回self。

例如,在下面的例子中,当获取X.attr的时候,Python自动运行Descriptor类的__get__方法,Subject.attr类属性分配给该方法(和特性一样,在Python 2.6中,要在这里使用描述符,我们必须派生自对象;在Python 3.0中,这是隐式的,但无伤大雅):

注意在第一个属性获取中自动传递到__get__方法中的参数,当获取X.attr的时候,就好像发生了如下的转换(尽管这里的Subject.attr没有再次调用__get__):

当描述符的实例参数为None的时候,该描述符知道将直接访问它。

只读描述符

正如前面提到的,和特性不同,使用描述符直接忽略__set__方法不足以让属性成为只读的,因为描述符名称可以赋给一个实例。在下面的例子中,对X.a的属性赋值在实例对象X中存储了a,由此,隐藏了存储在类C中的描述符:

这就是Python中所有实例属性赋值工作的方式,并且它允许在它们的实例中类选择性地覆盖类级默认值。要让基于描述符的属性成为只读的,捕获描述符类中的赋值并引发一个异常来阻止属性赋值——当要赋值的属性是一个描述符的时候,Python有效地绕过了常规实例层级的赋值行为,并且把操作指向描述符对象:

注意:还要注意不要把描述符__delete__方法和通用的__del__方法搞混淆了。调用前者是试图删除所有者类的一个实例上的管理属性名称;后者是一种通用的实例析构器方法,当任何类的一个实例将要进行垃圾回收的时候调用。__delete__与我们将要在本章后面遇到的__delattr__泛型属性删除方法关系更近。参见本书第29章了解关于操作符重载的更多内容。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文