# python3.7
Python 3.7.2 (default, Feb 15 2019, 16:54:46)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from collections.abc import *
>>> from _collections_abc import _check_methods
>>> class A:
... pass
...
>>> a = A()
>>> isinstance(a, Iterable)
False
>>> A.__iter__ = 100
>>> isinstance(a, Iterable) # why this not working?
False
>>> _check_methods(A, "__iter__")
True
>>> class B:
... def __iter__(self):
... pass
...
>>> isinstance(B(), Iterable)
True
我用A
修补了__iter__
,所以isinstance(a, Iterable)
应该返回True
,因为它现在已经很容易定义__iter__
了。从source中,Iterable
仅基于该类是否已实现__iter__
来确定。
那么为什么这个猴子补丁不能按我预期的那样工作?
答案 0 :(得分:3)
不支持动态实现(或取消实现)抽象方法。 abc
机制进行了大量的缓存,以加快isinstance
和issubclass
的检查速度,并且没有手动重置缓存的选项。 A
不是Iterable
的子类这一事实在第一次isinstance
调用之后被缓存,导致第二次调用产生False
的结果。
最接近docs来描述缓存行为的是以下行:
不动态地向类添加抽象方法,或在创建方法或类后尝试修改其抽象状态。
答案 1 :(得分:1)
您将变量:__iter__
添加到a
。您必须将其添加为这样的方法
class A:
pass
def foo(self):
pass
A.__iter__ = foo
a = A()
isinstance(a, Iterable)
# True
更新:此答案意外返回True。这只是返回True,因为我设置了 iter ,然后调用isinstance。如果我先调用isinstance然后设置 iter ,由于python缓存系统,它总是返回False(请阅读user2357112的答案)