Как я могу сделать класс или метод абстрактным в Python?
Я пытался переопределить __new__()
так:
class F:
def __new__(cls):
raise Exception("Unable to create an instance of abstract class %s" %cls)
но теперь, если я создам класс G
который наследует от F
так:
class G(F):
pass
тогда я не могу создать экземпляр G
, так как он вызывает __new__
метод своего суперкласса .
Есть ли лучший способ определить абстрактный класс?
python
class
inheritance
abstract-class
abstract
Мартин Тома
источник
источник
Ответы:
Используйте
abc
модуль для создания абстрактных классов. Используйтеabstractmethod
декоратор для объявления абстрактного метода и объявления абстрактного класса одним из трех способов, в зависимости от версии Python.В Python 3.4 и выше вы можете наследовать от
ABC
. В более ранних версиях Python метакласс вашего класса нужно указывать какABCMeta
. Указание метакласса имеет разный синтаксис в Python 3 и Python 2. Ниже показаны три возможности:Какой бы способ вы ни использовали, вы не сможете создать экземпляр абстрактного класса, который имеет абстрактные методы, но сможете создать экземпляр подкласса, который предоставляет конкретные определения этих методов:
источник
@abstractmethod
делает так, что декорированная функция должна быть переопределена до того, как будет создан экземпляр класса. Из документов:A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden.
@abstractmethod
для__init__
метода , а также, см stackoverflow.com/q/44800659/547270Старый способ (pre- PEP 3119 ) сделать это просто
raise NotImplementedError
в абстрактном классе, когда вызывается абстрактный метод.Это не обладает такими же хорошими свойствами, как при использовании
abc
модуля. Вы все еще можете создать экземпляр самого абстрактного базового класса, и вы не найдете свою ошибку, пока не вызовете абстрактный метод во время выполнения.Но если вы имеете дело с небольшим набором простых классов, возможно, с несколькими абстрактными методами, этот подход немного проще, чем пытаться просмотреть
abc
документацию.источник
Вот очень простой способ без использования модуля ABC.
В
__init__
методе класса, которым вы хотите быть абстрактным, вы можете проверить «тип» себя. Если тип self является базовым классом, то вызывающая сторона пытается создать экземпляр базового класса, поэтому выведите исключение. Вот простой пример:При запуске выдает:
Это показывает, что вы можете создать экземпляр подкласса, который наследуется от базового класса, но вы не можете создать экземпляр базового класса напрямую.
источник
Большинство предыдущих ответов были правильными, но вот ответ и пример для Python 3.7. Да, вы можете создать абстрактный класс и метод. Как напоминание, иногда класс должен определять метод, который логически принадлежит классу, но этот класс не может указать, как реализовать метод. Например, на следующих уроках «Родители и дети» они оба едят, но реализация будет отличаться для каждого, потому что дети и родители едят разные виды пищи, а количество раз, которое они едят, разное. Итак, подклассы метода переопределяют AbstractClass.eat.
ВЫВОД:
источник
import abc
, бесполезно.Этот будет работать в Python 3
источник
Как объяснено в других ответах, да, вы можете использовать абстрактные классы в Python, используя
abc
модуль . Ниже я приведу конкретный пример , используя абстрактные@classmethod
,@property
и@abstractmethod
( с помощью Python 3.6 +). Для меня обычно легче начать с примеров, которые я могу легко скопировать и вставить; Я надеюсь, что этот ответ также полезен для других.Давайте сначала создадим базовый класс с именем
Base
:Наш
Base
класс всегда будет иметь afrom_dict
classmethod
, aproperty
prop1
(который только для чтения) и aproperty
prop2
(который также может быть установлен), а также вызываемую функциюdo_stuff
. Какой бы класс сейчас не был построен на основеBase
, придется реализовать все это для методов / свойств. Обратите внимание, что для абстрактного метода требуются два декоратора -classmethod
и абстрактныйproperty
.Теперь мы можем создать такой класс
A
:Все необходимые методы / свойства реализованы, и мы можем, конечно, также добавить дополнительные функции, которые не являются частью
Base
(здесь:)i_am_not_abstract
.Теперь мы можем сделать:
При желании мы не можем установить
prop1
:вернется
Также наш
from_dict
метод работает отлично:Если мы теперь определили второй класс,
B
как это:и попытался создать экземпляр объекта следующим образом:
мы получим ошибку
список всех вещей,
Base
которые мы не реализовали вB
.источник
Также это работает и просто:
источник
Вы также можете использовать метод __new__ в своих интересах. Вы просто что-то забыли. Метод __new__ всегда возвращает новый объект, поэтому вы должны вернуть новый метод его суперкласса. Сделайте следующим образом.
При использовании нового метода вы должны возвращать объект, а не ключевое слово None. Это все, что вы пропустили.
источник
Я считаю принятый ответ, а все остальные странными, поскольку они переходят
self
в абстрактный класс. Абстрактный класс не создан, поэтому не может иметьself
.Так что попробуйте, это работает.
источник
источник
В своем фрагменте кода вы также можете решить эту проблему, предоставив реализацию для
__new__
метода в подклассе, аналогично:Но это взлом, и я советую вам против этого, если вы не знаете, что делаете. Почти во всех случаях я советую вам использовать
abc
модуль, который предлагали другие до меня.Кроме того, когда вы создаете новый (базовый) класс, сделать его подклассы
object
, например:class MyBaseClass(object):
. Я не знаю, насколько это важно, но это помогает сохранить согласованность стилей в вашем кодеисточник
Просто быстрое дополнение к ответу @ TimGilbert's old-school ... вы можете сделать так, чтобы метод init () вашего абстрактного базового класса выдавал исключение, и это предотвратило бы его создание, не так ли?
источник