返回介绍

10.3 协议和鸭子类型

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

在第 1 章我们就说过,在 Python 中创建功能完善的序列类型无需使用继承,只需实现符合序列协议的方法。不过,这里说的协议是什么呢?

在面向对象编程中,协议是非正式的接口,只在文档中定义,在代码中不定义。例如,Python 的序列协议只需要 __len__ 和 __getitem__ 两个方法。任何类(如 Spam),只要使用标准的签名和语义实现了这两个方法,就能用在任何期待序列的地方。Spam 是不是哪个类的子类无关紧要,只要提供了所需的方法即可。示例 1-1 中见过一例,这里再次给出代码,

如示例 10-3 所示。

示例 10-3 示例 1-1 的代码,为了方便,再次给出

import collections

Card = collections.namedtuple('Card', ['rank', 'suit'])

class FrenchDeck:
  ranks = [str(n) for n in range(2, 11)] + list('JQKA')
  suits = 'spades diamonds clubs hearts'.split()

  def __init__(self):
    self._cards = [Card(rank, suit) for suit in self.suits
                    for rank in self.ranks]

  def __len__(self):
    return len(self._cards)

  def __getitem__(self, position):
    return self._cards[position]

示例 10-3 中的 FrenchDeck 类能充分利用 Python 的很多功能,因为它实现了序列协议,不过代码中并没有声明这一点。任何有经验的 Python 程序员只要看一眼就知道它序列,即便它是 object 的子类也无妨。我们说它序列,因为它的行为像序列,这才是重点。

根据本章开头引用的 Alex Martelli 的帖子,人们称其为鸭子类型(duck typing)。

协议是非正式的,没有强制力,因此如果你知道类的具体使用场景,通常只需要实现一个协议的部分。例如,为了支持迭代,只需实现 __getitem__ 方法,没必要提供 __len__ 方法。

下面,我们将在 Vector 类中实现序列协议。我们先不支持完美的切片,稍后再完善。

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

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

发布评论

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