# 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
I patched A
with __iter__
, so isinstance(a, Iterable)
should returns True
, since it hehaves like an iterable now for having __iter__
defined. From the source, Iterable
determines only based on whether the class has __iter__
implemented.
So why does this monkey patch not working as I expected?
Dynamically implementing (or un-implementing) abstract methods isn't supported. The abc
machinery does a lot of caching to speed up isinstance
and issubclass
checks, and there's no option to manually reset the cache. The fact that A
isn't a subclass of Iterable
is cached after the first isinstance
call, causing a False
result for the second call.
The closest the docs come to describing the caching behavior is the following line:
Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported.