【问题标题】:why does isinstance check for abc.Sequence return False for custom classes?为什么 isinstance 检查 abc.Sequence 为自定义类返回 False?
【发布时间】:2021-02-15 15:20:45
【问题描述】:

我在abc python 模块文档中读到Sequence 是实现以下内容的东西:__getitem____len____contains____iter____reversed__indexcount

然而,当我运行以下示例时,它会产生错误:

from collections import abc

class Sequence():
    def __getitem__(self):
        pass
    def __len__(self):
        pass
    def index(self):
        pass
    def count(self):
        pass
    def __contains__(self):
        pass
    def __iter__(self):
        pass
    def __reversed__(self):
        pass

print(isinstance(Sequence(), abc.Sequence)) # False

当我为abc.Collectionabc.Reversed 做类似的事情来玩耍时,我得到了我期望的结果,例如,我创建了一个实现__contains____iter____len__ 的虚拟类,它是实际上被正确检测为abc.Collection 的实例。

你知道Sequence有什么问题吗?

编辑 1:

from collections import abc
class CustomIterable:
  def __iter__(self):
    pass
print(isinstance(CustomIterable(), abc.Iterable)) # True

即使我的自定义迭代不是来自abc,它仍然被识别为Iterable,因为它实现了__iter__ 特殊方法。

【问题讨论】:

标签: python python-3.x class types sequence


【解决方案1】:

您的自定义 Sequence 类与 abc.Sequence 类不同,因此 isinstance 将返回 false。

如果您正在寻找 True,您的自定义类需要继承自 abc.Sequence

class Sequence(abc.Sequence):
   .....

【讨论】:

  • 请在第一条消息中查看我的编辑(我无法弄清楚如何在 cmets 中格式化多行代码)。所以,我的自定义迭代确实被识别为Iterable,我认为这就是这些东西在幕后工作的方式。像我这样的例子似乎并不重要,因为如果我实现 __iter____getitem__ 我将能够在 for 循环等中使用它,但它可能会在静态代码分析中出现问题。如果我实现自己的类型,我认为它是一个序列,但实际上不是,然后在其上运行 mypy,我认为它可能会中断。
  • 即使你的例子对序列来说是正确的,那么为什么我的 edi1 例子表现得这样呢? CustomIterable 不是 abc.Iterable 并且它不继承自它,但它实际上是 abc.Iterable。知道这些东西是如何工作的吗?
【解决方案2】:

我今天也有类似的问题。

据我所知,collections.abc.Iterable 实现了自定义 __subclasshook__() 方法,而 collections.abc.Sequence 没有:

# _collections_abc.py

class Iterable(metaclass=ABCMeta):

    __slots__ = ()

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterable:
            return _check_methods(C, "__iter__") # True if __iter__ implemented
        return NotImplemented

这意味着如果一个类Foo 定义了所需的__iter__ 方法,那么isinstance(Foo(), collections.abc.Iterable) 将返回True

from collections.abc import Iterable

class Foo:
    def __iter__(self):
        return []

assert isinstance(Foo(), Iterable)

我不确定为什么 collections.abc.Iterable 实现了自定义的 __subclasshook__() 方法,而 collections.abc.Sequence 却没有。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-26
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-11
    • 2011-04-27
    相关资源
    最近更新 更多