ABC 拒绝我的子类,尽管它没有抽象方法
ABC refuses my subclass, despite it having no abstract methods
我有一个 collections.abc.MutableMapping
子类,它通过猴子修补实现了所需的抽象方法:
from collections.abc import MutableMapping
def make_wrappers(cls, methods = []):
"""This is used to eliminate code repetition, this file contains around 12
classes with similar rewirings of self.method to self.value.method
This approach is used instead of overriding __getattr__ and __getattribute__
because those are bypassed by magic methods like add()
"""
for method in methods:
def wrapper(self, *args, _method=method, **kwargs):
return getattr(self.value, _method)(*args, **kwargs)
setattr(cls, method, wrapper)
class MySubclass(MutableMapping):
def __init__(self, value = None):
value = {} if value is None else value
self.value = value
make_wrappers(
MySubclass,
['__delitem__', '__getitem__', '__iter__', '__len__', '__setitem__']
)
在尝试实例化 MySubclass 时,出现此错误:
>>> c = MySubclass({'a':a, 'b':b})
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
c = MySubclass({'a':1, 'b':2})
TypeError: Can't instantiate abstract class MySubclass with abstract methods __delitem__, __getitem__, __iter__, __len__, __setitem__
但这行得通:
>>> MySubclass.__setitem__
<function make_wrappers.<locals>.wrapper at 0x0000020F76A24AF0>
如何强制实例化?
我 知道 这些方法有效,因为当我在 MySubclass
和 collections.abc.MutableMapping
之间放置一个额外的继承层时,它们神奇地起作用了!
正在创建 ABC
creates a set of missing abstract methods as soon as the class is created。必须清除此项以允许实例化 class.
>>> # setup as before
>>> MySubclass.__abstractmethods__
frozenset({'__delitem__', '__getitem__', '__iter__', '__len__', '__setitem__'})
>>> MySubclass({'a':a, 'b':b})
# TypeError: Can't instantiate abstract class MySubclass with abstract methods __delitem__, __getitem__, __iter__, __len__, __setitem__
>>> MySubclass.__abstractmethods__ = frozenset() # clear cache of abstract methods
>>> MySubclass({'a':a, 'b':b})
<__main__.MySubclass at 0x1120a9340>
请注意 .__abstractmethods__
不是 Python Data Model or abc
specification 的一部分。考虑它的版本和具体实现——总是测试你的目标 version/implementation 是否使用它。但是,它应该适用于 CPython(Py3.6 和 Py3.9 上的测试)和 PyPy3(Py3.6 上的测试)。
可以调整包装函数以自动从抽象方法缓存中删除 monkey-patched 方法。如果所有方法都被修补,这使得 class 有资格实例化。
def make_wrappers(cls, methods = []):
"""This is used to eliminate code repetition, this file contains around 12
classes with similar rewirings of self.method to self.value.method
This approach is used instead of overriding __getattr__ and __getattribute__
because those are bypassed by magic methods like add()
"""
for method in methods:
def wrapper(self, *args, _method=method, **kwargs):
return getattr(self.value, _method)(*args, **kwargs)
setattr(cls, method, wrapper)
cls.__abstractmethods__ = cls.__abstractmethods__.difference(methods)
我有一个 collections.abc.MutableMapping
子类,它通过猴子修补实现了所需的抽象方法:
from collections.abc import MutableMapping
def make_wrappers(cls, methods = []):
"""This is used to eliminate code repetition, this file contains around 12
classes with similar rewirings of self.method to self.value.method
This approach is used instead of overriding __getattr__ and __getattribute__
because those are bypassed by magic methods like add()
"""
for method in methods:
def wrapper(self, *args, _method=method, **kwargs):
return getattr(self.value, _method)(*args, **kwargs)
setattr(cls, method, wrapper)
class MySubclass(MutableMapping):
def __init__(self, value = None):
value = {} if value is None else value
self.value = value
make_wrappers(
MySubclass,
['__delitem__', '__getitem__', '__iter__', '__len__', '__setitem__']
)
在尝试实例化 MySubclass 时,出现此错误:
>>> c = MySubclass({'a':a, 'b':b})
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
c = MySubclass({'a':1, 'b':2})
TypeError: Can't instantiate abstract class MySubclass with abstract methods __delitem__, __getitem__, __iter__, __len__, __setitem__
但这行得通:
>>> MySubclass.__setitem__
<function make_wrappers.<locals>.wrapper at 0x0000020F76A24AF0>
如何强制实例化?
我 知道 这些方法有效,因为当我在 MySubclass
和 collections.abc.MutableMapping
之间放置一个额外的继承层时,它们神奇地起作用了!
正在创建 ABC
creates a set of missing abstract methods as soon as the class is created。必须清除此项以允许实例化 class.
>>> # setup as before
>>> MySubclass.__abstractmethods__
frozenset({'__delitem__', '__getitem__', '__iter__', '__len__', '__setitem__'})
>>> MySubclass({'a':a, 'b':b})
# TypeError: Can't instantiate abstract class MySubclass with abstract methods __delitem__, __getitem__, __iter__, __len__, __setitem__
>>> MySubclass.__abstractmethods__ = frozenset() # clear cache of abstract methods
>>> MySubclass({'a':a, 'b':b})
<__main__.MySubclass at 0x1120a9340>
请注意 .__abstractmethods__
不是 Python Data Model or abc
specification 的一部分。考虑它的版本和具体实现——总是测试你的目标 version/implementation 是否使用它。但是,它应该适用于 CPython(Py3.6 和 Py3.9 上的测试)和 PyPy3(Py3.6 上的测试)。
可以调整包装函数以自动从抽象方法缓存中删除 monkey-patched 方法。如果所有方法都被修补,这使得 class 有资格实例化。
def make_wrappers(cls, methods = []):
"""This is used to eliminate code repetition, this file contains around 12
classes with similar rewirings of self.method to self.value.method
This approach is used instead of overriding __getattr__ and __getattribute__
because those are bypassed by magic methods like add()
"""
for method in methods:
def wrapper(self, *args, _method=method, **kwargs):
return getattr(self.value, _method)(*args, **kwargs)
setattr(cls, method, wrapper)
cls.__abstractmethods__ = cls.__abstractmethods__.difference(methods)