鸭子打字的猴子补丁
monkey patching for duck typing
# 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
我用 __iter__
修补了 A
,所以 isinstance(a, Iterable)
应该 returns True
,因为它现在像一个可迭代的对象了 __iter__
] 定义。从 source 开始,Iterable
仅根据 class 是否已实施 __iter__
来确定。
那么为什么这个猴子补丁没有像我预期的那样工作?
您将变量 __iter__
添加到 a
。您必须将其添加为这样的方法:
class A:
pass
def foo(self):
pass
A.__iter__ = foo
a = A()
isinstance(a, Iterable)
# True
更新:这个答案不小心 returns 正确。这只是 returns True 因为我设置了 iter 然后调用了 isinstance。如果我先调用 isinstance 然后设置 iter 它总是 returns False 因为 python 缓存系统(阅读 user2357112 的答案)
不支持动态实现(或取消实现)抽象方法。 abc
机器做了很多缓存来加速 isinstance
和 issubclass
检查,并且没有手动重置缓存的选项。 A
不是 Iterable
的子类这一事实在第一次 isinstance
调用后被缓存,导致第二次调用的结果为 False
。
最接近 docs 来描述缓存行为的是以下行:
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.
# 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
我用 __iter__
修补了 A
,所以 isinstance(a, Iterable)
应该 returns True
,因为它现在像一个可迭代的对象了 __iter__
] 定义。从 source 开始,Iterable
仅根据 class 是否已实施 __iter__
来确定。
那么为什么这个猴子补丁没有像我预期的那样工作?
您将变量 :__iter__
添加到 a
。您必须将其添加为这样的方法
class A:
pass
def foo(self):
pass
A.__iter__ = foo
a = A()
isinstance(a, Iterable)
# True
更新:这个答案不小心 returns 正确。这只是 returns True 因为我设置了 iter 然后调用了 isinstance。如果我先调用 isinstance 然后设置 iter 它总是 returns False 因为 python 缓存系统(阅读 user2357112 的答案)
不支持动态实现(或取消实现)抽象方法。 abc
机器做了很多缓存来加速 isinstance
和 issubclass
检查,并且没有手动重置缓存的选项。 A
不是 Iterable
的子类这一事实在第一次 isinstance
调用后被缓存,导致第二次调用的结果为 False
。
最接近 docs 来描述缓存行为的是以下行:
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.