返回介绍

20.3 方法是描述符

发布于 2024-02-05 21:59:47 字数 2945 浏览 0 评论 0 收藏 0

在类中定义的函数属于绑定方法(bound method),因为用户定义的函数都有 __get__ 方法,所以依附到类上时,就相当于描述符。示例 20-13 演示了从示例 20-8 里定义的 Managed 类中读取 spam 方法。

示例 20-13 方法是非覆盖型描述符

  >>> obj = Managed()
  >>> obj.spam  ➊
  <bound method Managed.spam of <descriptorkinds.Managed object at 0x74c80c>>
  >>> Managed.spam  ➋
  <function Managed.spam at 0x734734>
  >>> obj.spam = 7  ➌
  >>> obj.spam
  7

❶ obj.spam 获取的是绑定方法对象。

❷ 但是 Managed.spam 获取的是函数。

❸ 如果为 obj.spam 赋值,会遮盖类属性,导致无法通过 obj 实例访问 spam 方法。

函数没有实现 __set__ 方法,因此是非覆盖型描述符,如示例 20-13 中的最后一行所示。

从示例 20-13 中还可以看出一个重要信息:obj.spam 和 Managed.spam 获取的是不同的对象。与描述符一样,通过托管类访问时,函数的 __get__ 方法会返回自身的引用。但是,通过实例访问时,函数的 __get__ 方法返回的是绑定方法对象:一种可调用的对象,里面包装着函数,并把托管实例(例如 obj)绑定给函数的第一个参数(即 self),这与 functools.partial 函数的行为一致(参见 5.10.2 节)。

为了深入理解这种机制,请看示例 20-14。

示例 20-14 method_is_descriptor.py:Text 类,继承自 UserString 类

import collections


class Text(collections.UserString):

  def __repr__(self):
    return 'Text({!r})'.format(self.data)

  def reverse(self):
    return self[::-1]

下面来分析 Text.reverse 方法,如示例 20-15 所示。

示例 20-15 测试一个方法

  >>> word = Text('forward')
  >>> word  ➊
  Text('forward')
  >>> word.reverse()  ➋
  Text('drawrof')
  >>> Text.reverse(Text('backward'))  ➌
  Text('drawkcab')
  >>> type(Text.reverse), type(word.reverse)  ➍
  (<class 'function'>, <class 'method'>)
  >>> list(map(Text.reverse, ['repaid', (10, 20, 30), Text('stressed')]))  ➎
  ['diaper', (30, 20, 10), Text('desserts')]
  >>> Text.reverse.__get__(word)  ➏
  <bound method Text.reverse of Text('forward')>
  >>> Text.reverse.__get__(None, Text)  ➐
  <function Text.reverse at 0x101244e18>
  >>> word.reverse  ➑
  <bound method Text.reverse of Text('forward')>
  >>> word.reverse.__self__  ➒
  Text('forward')
  >>> word.reverse.__func__ is Text.reverse  ➓
  True

❶ Text 实例的 repr 方法返回一个类似 Text 构造方法调用的字符串,可用于创建相同的实例。

❷ reverse 方法返回反向拼写的单词。

❸ 在类上调用方法相当于调用函数。

❹ 注意类型是不同的,一个是 function,一个是 method。

❺ Text.reverse 相当于函数,甚至可以处理 Text 实例之外的其他对象。

❻ 函数都是非覆盖型描述符。在函数上调用 __get__ 方法时传入实例,得到的是绑定到那个实例上的方法。

❼ 调用函数的 __get__ 方法时,如果 instance 参数的值是 None,那么得到的是函数本身。

❽ word.reverse 表达式其实会调用 Text.reverse.__get__(word),返回对应的绑定方法。

❾ 绑定方法对象有个 __self__ 属性,其值是调用这个方法的实例引用。

❿ 绑定方法的 __func__ 属性是依附在托管类上那个原始函数的引用。

绑定方法对象还有个 __call__ 方法,用于处理真正的调用过程。这个方法会调用 __func__ 属性引用的原始函数,把函数的第一个参数设为绑定方法的 __self__ 属性。这就是形参 self 的隐式绑定方式。

函数会变成绑定方法,这是 Python 语言底层使用描述符的最好例证。

深入了解描述符和方法的运作方式之后,下面讨论用法方面的一些实用建议。

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

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

发布评论

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