Вот что я нашел: если вы установите атрибут __abstractmethods__
как пустой набор, вы сможете создать экземпляр абстрактного класса.Это поведение указано в PEP 3119 :
Если результирующий набор __abstractmethods__
не пуст, класс считается абстрактным и при попытке его создания будет вызван TypeError.
Так что вам просто нужно очистить этот атрибут на время тестов.
>>> import abc
>>> class A(metaclass = abc.ABCMeta):
... @abc.abstractmethod
... def foo(self): pass
Вы не можете создать экземпляр A:
>>> A()
Traceback (most recent call last):
TypeError: Can't instantiate abstract class A with abstract methods foo
Если вы переопределите __abstractmethods__
, вы можете:
>>> A.__abstractmethods__=set()
>>> A() #doctest: +ELLIPSIS
<....A object at 0x...>
Работает в обоих направлениях:
>>> class B(object): pass
>>> B() #doctest: +ELLIPSIS
<....B object at 0x...>
>>> B.__abstractmethods__={"foo"}
>>> B()
Traceback (most recent call last):
TypeError: Can't instantiate abstract class B with abstract methods foo
Вы также можете использовать unittest.mock
(из 3.3) для временного переопределения поведения ABC.
>>> class A(metaclass = abc.ABCMeta):
... @abc.abstractmethod
... def foo(self): pass
>>> from unittest.mock import patch
>>> p = patch.multiple(A, __abstractmethods__=set())
>>> p.start()
{}
>>> A() #doctest: +ELLIPSIS
<....A object at 0x...>
>>> p.stop()
>>> A()
Traceback (most recent call last):
TypeError: Can't instantiate abstract class A with abstract methods foo