使用 ABC 时是否需要 isinstance 检查?

Do I need isinstance checks when using ABCs?

这是“Fluent Python”一书中的界面示例:

from abc import ABCMeta, abstractmethod

class IStream(metaclass=ABCMeta):
    @abstractmethod
    def read(self, maxbytes=-1):
        pass

    @abstractmethod
    def write(self, data):
        pass

本书更进一步,可以读到“显式检查此接口的代码可以如下编写”:

def serialize(obj, stream):
    if not isinstance(stream, IStream):
        raise TypeError('Expected an IStream")

我的问题是:为什么我需要这样的 isinstance 检查?是否适用于 stream 可能是不从 IStream 继承的 class 的实例的情况?

否则,我的理解是不需要它,因为如果作为 stream 传递的实例不满足 IStream 接口(通过从 ABC 继承),它会不允许在它通过之前实例化:

class Stream(IStream):
  def read(self):
    pass

  def WRITE(self):
    pass

stream = Stream()

Traceback (most recent call last): File "c:\python projects\test.py", line 18, in stream = Stream() TypeError: Can't instantiate abstract class Stream with abstract method write

元class 限制了您被允许做的事情/在开发实现它的 class 时强制您做某些事情。

然而,像serialize这样的方法是class本身的方法,以实例作为参数——使用你的class的人绝不会被迫传递它正确 class.

的对象

编辑器或 IDE 可能会告诉他们他们正在传递一个 class 的对象,这不是预期的 - 当您添加清晰的类型提示时更是如此,但即便如此不会被完全禁止。

你要么需要假设它被正确使用,要么相信当你的方法试图用它不支持的传递的实例参数做一些事情时,你的代码会失败并出现适当的异常(本着鸭子类型的精神),或使用 isinstance.

明确检查它是否正确 class

通常,我只检查使用 isinstance,如果我编写的代码可能仅仅因为将错误类型的对象传递给它而产生潜在的灾难性影响——这种情况很少见。在大多数情况下,类型提示就足够了。