返回介绍

11.1 Python 文化中的接口和协议

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

引入抽象基类之前,Python 就已经非常成功了,即便现在也很少有代码使用抽象基类。第 1 章就已经讨论了鸭子类型和协议。在 10.3 节,我们把协议定义为非正式的接口,是让 Python 这种动态类型语言实现多态的方式。

接口在动态类型语言中是怎么运作的呢?首先,基本的事实是,Python 语言没有 interface 关键字,而且除了抽象基类,每个类都有接口:类实现或继承的公开属性(方法或数据属性),包括特殊方法,如 __getitem__ 或 __add__。

按照定义,受保护的属性和私有属性不在接口中:即便“受保护的”属性也只是采用命名约定实现的(单个前导下划线);私有属性可以轻松地访问(参见 9.7 节),原因也是如此。不要违背这些约定。

另一方面,不要觉得把公开数据属性放入对象的接口中不妥,因为如果需要,总能实现读值方法和设值方法,把数据属性变成特性,使用 obj.attr 句法的客户代码不会受到影响。 Vector2d 类就是这么做的,示例 11-1 是 Vector2d 类的第一版,x 和 y 是公开属性。

示例 11-1 vector2d_v0.py:x 和 y 是公开数据属性(代码与示例 9-2 相同)

class Vector2d:
  typecode = 'd'

  def __init__(self, x, y):
    self.x = float(x)
    self.y = float(y)

  def __iter__(self):
    return (i for i in (self.x, self.y))

  # 下面是其他方法(这个代码清单将其省略了)

在示例 9-7 中,我们把 x 和 y 变成了只读特性(见示例 11-2)。这是一项重大重构,但是 Vector2d 的接口基本没变:用户仍能读取 my_vector.x 和 my_vector.y。

示例 11-2 vector2d_v3.py:使用特性实现 x 和 y(完整的代码清单参见示例 9-9)

class Vector2d:
  typecode = 'd'

  def __init__(self, x, y):
    self.__x = float(x)
    self.__y = float(y)

  @property
  def x(self):
    return self.__x

  @property
  def y(self):
    return self.__y

  def __iter__(self):
    return (i for i in (self.x, self.y))

  # 下面是其他方法(这个代码清单将其省略了)

关于接口,这里有个实用的补充定义:对象公开方法的子集,让对象在系统中扮演特定的角色。Python 文档中的“文件类对象”或“可迭代对象”就是这个意思,这种说法指的不是特定的类。接口是实现特定角色的方法集合,这样理解正是 Smalltalk 程序员所说的协议,其他动态语言社区都借鉴了这个术语。协议与继承没有关系。一个类可能会实现多个接口,从而让实例扮演多个角色。

协议是接口,但不是正式的(只由文档和约定定义),因此协议不能像正式接口那样施加限制(本章后面会说明抽象基类对接口一致性的强制)。一个类可能只实现部分接口,这是允许的。有时,某些 API 只要求“文件类对象”返回字节序列的 .read() 方法。在特定的上下文中可能需要其他文件操作方法,也可能不需要。

写作本书时,Python 3 中 memoryview 的文档说,它能处理“支持缓冲协议的对象”,不过缓冲协议的文档是针对 C API 的。bytearray(https://docs.python.org/3/library/functions.html#bytearray) 的构造方法接受“一个符合缓冲接口的对象”。如今,文档正在改变用词,使用“字节序列类对象”这样更加友好的表述。2 我指出这一点是为了强调,对 Python 程序员来说,“X 类对象”“X 协议”和“X 接口”都是一个意思。

2其实,Issue 16518:“add buffer protocol to glossary”做的就是这种修改,把很多“支持缓冲协议 / 接口 /API 的对象”改成了“字节序列类对象”;“Other mentions of the buffer protocol”也是如此。

序列协议是 Python 最基础的协议之一。即便对象只实现了那个协议最基本的一部分,解释器也会负责任地处理,如下一节所示。

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

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

发布评论

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