isinstance 函数似乎施加魔法,可以自动判断?

2021-05-14 15:42:02 +08:00
 James369

我在构造一个自定义迭代器 Test 类的时候发现一个奇特的现象,Test 类并没有继承自 Iterable,只是实现了__iter__和__next__函数。

然而创建的对象却可以判定是 Iterable 类型

class TestIterator():
    def __init__(self, n):
        ...
    def __iter__(self):
        return self
    def __next__(self):
        ...

t1 = Test()
isinstance(t1, Iterable)   #返回 True !!!

然后我又创建了一组普通的类测试,发现又不行了:

class A:
    def do1(self):
        print('A do1')
class B(A):
    def do2(self):
        print('B do2')
class X:
    def do1(self):
        print('X do1')

a1 = A()
b1 = B()
x1 = X()

isinstance(b1, A)    #True
isinstance(x1, A)    #False ???
1501 次点击
所在节点    Python
4 条回复
fengjianxinghun
2021-05-14 15:55:00 +08:00
假如你看起来像鸭子,叫起来像鸭子,走起路来像鸭子,那你就是鸭子。


https://docs.python.org/3/library/stdtypes.html#typeiter
knightdf
2021-05-14 15:57:53 +08:00
建议你看看 collections.abc.Iterable 的文档
geelaw
2021-05-14 16:33:19 +08:00
答案是因为 Iterable 是抽象基类 (abstract base class),但 A 不是。isinstance 对于抽象基类 (ABC) 有特殊的规则。

https://docs.python.org/3/library/functions.html#isinstance

当 object 是 classinfo 或它(直接、间接、虚拟)子类的实例时,返回 True 。

点击“虚拟”,可以看到

https://docs.python.org/3/glossary.html#term-abstract-base-class

ABC 引入虚拟子类——虽然不继承,但 isinstance()、issubclass() 仍然识别为子类。
abersheeran
2021-05-14 16:53:22 +08:00
https://docs.python.org/3/reference/datamodel.html?highlight=instancecheck#class.__instancecheck__ 为你的 A 实现一个 __instancecheck__ 用以检查 do1 是否存在就行。

如果你觉得手工穷举检查麻烦,可以使用 https://docs.python.org/zh-cn/3/library/typing.html#typing.runtime_checkable

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/776940

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX