为什么 Python 无法推断出我的类遵循 Sequence 协议?

Why can't Python infer that my class follows the Sequence protocol?

提问人:Alexander Soare 提问时间:8/10/2023 最后编辑:Alexander Soare 更新时间:8/10/2023 访问量:43

问:

我希望如果我编写一个按照 https://docs.python.org/3.10/library/collections.abc.html 实现所需的所有方法的类,Python 将使用鸭子类型来知道它的实例是 Sequence,但我发现情况并非如此:Sequence

from collections.abc import Sequence

class MySequence:
    def __getitem__(self, ix):
        pass
    
    def __iter__(self):
        pass
    
    def __len__(self):
        pass
    
    def __contains__(self, val):
        pass
    
    def __reversed__(self):
        pass
    
    def count(self, val):
        pass
    
    def index(self, val):
        pass

seq = MySequence()
print(isinstance(seq, Sequence))

这将打印 False 而不是 True。为什么?

python 鸭子类型

评论

0赞 Brian61354270 8/10/2023
def __getitem__(self):不兼容(甚至不可用?查看object.__getitem__Sequence
0赞 Alexander Soare 8/10/2023
我不认为鸭子打字机制实际上检查了函数的参数。是吗?这就是你要得到的吗?@Brian61354270
0赞 Alexander Soare 8/10/2023
为避免疑义,我将更新我的代码片段,以便所有函数签名都采用正确数量的参数(并且我已经验证了结果仍然相同)。

答:

4赞 wim 8/10/2023 #1

这里没有鸭子打字。如果你根本没有从 abc 继承,那么你需要注册你的类:Sequence

Sequence.register(MySequence)

文档中关于鸭子打字的第 3 点:

一些简单的接口可以通过所需方法的存在直接识别

...

复杂接口不支持最后一种技术,因为接口不仅仅是方法名称的存在。接口指定方法之间的语义和关系,这些语义和关系不能仅从特定方法名称的存在中推断出来。例如,知道一个类提供 、 和 不足以区分 a 和 。__getitem____len____iter__SequenceMapping

评论

2赞 Brian61354270 8/10/2023
您可以参考的另一个文档链接:docs.python.org/3/glossary.html#term-sequence“collections.abc.Sequence 抽象基类定义了一个更丰富的接口......实现此扩展接口的类型可以使用 register() 显式注册。
0赞 Alexander Soare 8/10/2023
好吧,所以我想这个解释仍然为返回 True(确实如此)留下了空间,对吧?因为也许不是一个“复杂的界面”。isinstance(seq, Container)Container
0赞 wim 8/10/2023
右。它应该是不需要注册的实例。collections.abc.Iterable
0赞 Alexander Soare 8/10/2023
需要明确的是,你只是想写吗?不知道从哪里来。abc.Containerabc.Iterable
3赞 Brian61354270 8/10/2023
@AlexanderSoare我认为 wim 只是提供了一个不需要注册的 ABC 的例子。事实上,此表中标有脚注的任何 ABC 都不需要显式注册。[1]