Python: абстрактный класс __init__
Я пытаюсь объявить абстрактный класс A
конструктором со стандартным поведением: все подклассы должны инициализировать элемент self.n
:
from abc import ABCMeta
class A(object):
__metaclass__ = ABCMeta
def __init__(self, n):
self.n = n
Однако я не хочу, чтобы класс A
был создан, потому что, ну, это абстрактный класс. Проблема в том, что это действительно разрешено:
a = A(3)
Это не вызывает ошибок, когда я ожидаю, что это произойдет.
Итак: как я могу определить неинтуитивный абстрактный класс, определяя поведение по умолчанию для конструктора?
Ответы
Ответ 1
Создание __init__
абстрактного метода:
from abc import ABCMeta, abstractmethod
class A(object):
__metaclass__ = ABCMeta
@abstractmethod
def __init__(self, n):
self.n = n
if __name__ == '__main__':
a = A(3)
помогает:
TypeError: Can't instantiate abstract class A with abstract methods __init__
Версия Python 3:
from abc import ABCMeta, abstractmethod
class A(object, metaclass=ABCMeta):
@abstractmethod
def __init__(self, n):
self.n = n
if __name__ == '__main__':
a = A(3)
Работает также:
TypeError: Can't instantiate abstract class A with abstract methods __init__
Ответ 2
Вы должны также определить методы как абстрактные, так и с декоратором @abc.abstractmethod
.
Ответ 3
Вы можете переопределить метод __new__
, чтобы предотвратить прямую конкретизацию.
class A(object):
__metaclass__ = ABCMeta
def __new__(cls, *args, **kwargs):
if cls is A:
raise TypeError(
"TypeError: Can't instantiate abstract class {name} directly".format(name=cls.__name__)
)
return object.__new__(cls)
Вывод:
>>> A()
Traceback (most recent call last):
File "<ipython-input-8-3cd318a12eea>", line 1, in <module>
A()
File "/Users/ashwini/py/so.py", line 11, in __new__
"TypeError: Can't instantiate abstract class {name} directly".format(name=cls.__name__)
TypeError: TypeError: Can't instantiate abstract class A directly
Ответ 4
Не очень элегантное решение может быть таким:
class A(object):
def __init__(self, n):
if self.__class__ == A:
raise Exception('I am abstract!')
self.n = n
Использование
class B(A):
pass
a = A(1) # Will throw exception
b = B(1) # Works fine as expected.