Разница между абстрактным классом и интерфейсом в Python

В чем разница между абстрактным классом и интерфейсом в Python?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
576
0
420 271
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

У Python на самом деле нет ни того, ни другого.

Он использует утиную печать, что устраняет необходимость в интерфейсах (по крайней мере, для компьютера :-))

Python <= 2.5: Очевидно, что базовые классы существуют, но нет явного способа пометить метод как «чисто виртуальный», поэтому класс на самом деле не является абстрактным.

Python> = 2.6: Абстрактные базовые классы делают существовать (http://docs.python.org/library/abc.html). И позволяют указать методы, которые должны быть реализованы в подклассах. Синтаксис мне не очень нравится, но особенность есть. В большинстве случаев, вероятно, лучше использовать утиную печать со стороны «использующего» клиента.

Python 3.0 действительно добавляет реальные абстрактные базовые классы. Они используются в модуле коллекций, а также в других местах. docs.python.org/3.0/library/abc.html

Lara Dougan 16.12.2008 21:11

Ссылка на то, почему утка устраняет необходимость в интерфейсах, была бы полезна. Мне не кажется очевидным, что утиная типизация, которую я понимаю как способность «высовывать» любой метод или атрибут на любой объект, будет означать, что вам не нужно указывать требуемое поведение (и заставлять компилятор напоминать вам для их реализации), именно так я понимаю абстрактные базовые классы.

Reb.Cabin 07.04.2018 00:38

Это не столько утка, сколько поддержка множественного наследования, которое удаляет искусственную границу между интерфейсом и абстрактным классом, например, Ява нарисовала.

omni 19.04.2019 08:37

Python> = 2.6 имеет Абстрактные базовые классы.

Abstract Base Classes (abbreviated ABCs) complement duck-typing by providing a way to define interfaces when other techniques like hasattr() would be clumsy. Python comes with many builtin ABCs for data structures (in the collections module), numbers (in the numbers module), and streams (in the io module). You can create your own ABC with the abc module.

Также есть модуль Zope Интерфейс, который используется проектами вне zope, например twisted. Я не очень знаком с этим, но есть вики-страница здесь, которая может помочь.

В общем, вам не нужна концепция абстрактных классов или интерфейсов в python (отредактировано - подробности см. В ответе S.Lott).

Что вы получаете, используя азбуку в Python?

CpILL 18.05.2018 02:19
Ответ принят как подходящий

Иногда вы увидите следующее:

class Abstract1:
    """Some description that tells you it's abstract,
    often listing the methods you're expected to supply."""

    def aMethod(self):
        raise NotImplementedError("Should have implemented this")

Поскольку Python не имеет (и не нуждается) в формальном контракте интерфейса, различия в стиле Java между абстракцией и интерфейсом не существует. Если кто-то попытается определить формальный интерфейс, он также будет абстрактным классом. Единственные отличия заключаются в заявленном намерении в строке документации.

И разница между абстрактным и интерфейсом просто потрясающая, когда вы печатаете уткой.

Java использует интерфейсы, потому что не имеет множественного наследования.

Поскольку Python имеет множественное наследование, вы также можете увидеть что-то вроде этого

class SomeAbstraction:
    pass  # lots of stuff - but missing something

class Mixin1:
    def something(self):
        pass  # one implementation

class Mixin2:
    def something(self):
        pass  # another

class Concrete1(SomeAbstraction, Mixin1):
    pass

class Concrete2(SomeAbstraction, Mixin2):
    pass

Это использует своего рода абстрактный суперкласс с миксинами для создания конкретных подклассов, которые не пересекаются.

С. Лотт, вы имеете в виду, что из-за утиного ввода различие между has-a (интерфейс) и is-a (наследование) несущественно?

Lorenzo 13.09.2011 01:58

Разница между абстрактным и интерфейсом просто потрясающая, когда вы печатаете уткой. Я не знаю, что значит «существенный». Это «реально» - в нем есть содержание - с точки зрения дизайна. Но с точки зрения языка поддержки может не быть. Вы можете принять соглашения, чтобы различать абстрактный класс и определение класса интерфейса в Python.

S.Lott 13.09.2011 02:00

@ L.DeLeo - вы уверены, что ваше представление о том, что есть-а или есть-а, верно? Я обычно рассматриваю различие как has-a = переменную-член против наследования is-a = (интерфейс родительского класса или же). Think Comparable или List на Java; это отношения «есть-а», независимо от того, являются ли они интерфейсами или абстрактными классами.

dimo414 17.06.2012 08:38
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__)) - более информативное сообщение об ошибке :)
naught101 03.09.2014 05:43

@Lorenzo отношения has-a не имеют ничего общего с наследованием, утиной типизацией, интерфейсами и абстрактными классами (все четыре относятся к отношениям is-a).

Karl Richter 30.08.2015 16:29

Python мне не нужен формальный интерфейсный контракт, но python не пишет сам, люди. Интерфейсы помогают люди писать и делиться кодом. Компьютерам нужны двоичные файлы, людям нужны языки.

CpILL 18.10.2019 02:13

Как правило, интерфейсы используются только в языках, использующих модель классов с единичным наследованием. В этих языках с единичным наследованием интерфейсы обычно используются, если какой-либо класс может использовать определенный метод или набор методов. Также в этих языках с одним наследованием абстрактные классы используются либо для определения переменных класса в дополнение к отсутствию или нескольким методам, либо для использования модели с одним наследованием для ограничения диапазона классов, которые могут использовать набор методов.

Языки, поддерживающие модель множественного наследования, как правило, используют только классы или абстрактные базовые классы, а не интерфейсы. Поскольку Python поддерживает множественное наследование, он не использует интерфейсы, и вы можете использовать базовые классы или абстрактные базовые классы.

http://docs.python.org/library/abc.html

Проще говоря: Интерфейс похож на пустую форму для маффинов. Это файл класса с набором определений методов, не имеющих кода.

Абстрактный класс - это то же самое, но не все функции должны быть пустыми. У некоторых может быть код. Он не совсем пустой.

Зачем дифференцировать: В Python нет особой практической разницы, но на уровне планирования для большого проекта можно чаще говорить об интерфейсах, поскольку здесь нет кода. Особенно, если вы работаете с программистами на Java, которые привыкли к этому термину.

+1 за различие, когда ABC может иметь собственные реализации - что кажется очень крутым способом перехитрить себя

Titou 16.09.2016 11:29

What is the difference between abstract class and interface in Python?

Интерфейс для объекта - это набор методов и атрибутов этого объекта.

В Python мы можем использовать абстрактный базовый класс для определения и обеспечения интерфейса.

Использование абстрактного базового класса

Например, предположим, что мы хотим использовать один из абстрактных базовых классов из модуля collections:

import collections
class MySet(collections.Set):
    pass

Если мы попытаемся использовать его, мы получим TypeError, потому что созданный нами класс не поддерживает ожидаемое поведение наборов:

>>> MySet()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__

Таким образом, мы должны реализовать в наименее__contains__, __iter__ и __len__. Воспользуемся этим примером реализации из документация:

class ListBasedSet(collections.Set):
    """Alternate set implementation favoring space over speed
    and not requiring the set elements to be hashable. 
    """
    def __init__(self, iterable):
        self.elements = lst = []
        for value in iterable:
            if value not in lst:
                lst.append(value)
    def __iter__(self):
        return iter(self.elements)
    def __contains__(self, value):
        return value in self.elements
    def __len__(self):
        return len(self.elements)

s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2

Реализация: создание абстрактного базового класса

Мы можем создать наш собственный абстрактный базовый класс, установив метакласс на abc.ABCMeta и используя декоратор abc.abstractmethod для соответствующих методов. Метакласс будет добавлять декорированные функции к атрибуту __abstractmethods__, предотвращая создание экземпляров до тех пор, пока они не будут определены.

import abc

Например, «effable» определяется как что-то, что можно выразить словами. Скажем, мы хотели определить абстрактный базовый класс, который является эффективным, в Python 2:

class Effable(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

Или в Python 3 с небольшим изменением объявления метакласса:

class Effable(object, metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

Теперь, если мы попытаемся создать эффективный объект без реализации интерфейса:

class MyEffable(Effable): 
    pass

и попытайтесь создать его экземпляр:

>>> MyEffable()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__

Нам говорят, что мы не закончили работу.

Теперь, если мы согласимся, предоставив ожидаемый интерфейс:

class MyEffable(Effable): 
    def __str__(self):
        return 'expressable!'

затем мы можем использовать конкретную версию класса, производного от абстрактного:

>>> me = MyEffable()
>>> print(me)
expressable!

Есть и другие вещи, которые мы могли бы сделать с этим, например, зарегистрировать виртуальные подклассы, которые уже реализуют эти интерфейсы, но я думаю, что это выходит за рамки этого вопроса. Однако другие продемонстрированные здесь методы должны адаптировать этот метод с помощью модуля abc.

Заключение

Мы продемонстрировали, что создание абстрактного базового класса определяет интерфейсы для пользовательских объектов в Python.

Абстрактные классы - это классы, содержащие один или несколько абстрактных методов. Наряду с абстрактными методами абстрактные классы могут иметь статические методы, методы класса и экземпляра. Но в случае интерфейса у него будут только абстрактные методы, а не другие. Следовательно, наследование абстрактного класса не обязательно, но обязательно наследовать интерфейс.

Для полноты картины упомянем PEP3119 где ABC был представлен и сравнен с интерфейсами, и оригинальный комментарий Талина.

Абстрактный класс - это не идеальный интерфейс:

  • принадлежит иерархии наследования
  • изменчив

Но если вы думаете написать это по-своему:

def some_function(self):
     raise NotImplementedError()

interface = type(
    'your_interface', (object,),
    {'extra_func': some_function,
     '__slots__': ['extra_func', ...]
     ...
     '__instancecheck__': your_instance_checker,
     '__subclasscheck__': your_subclass_checker
     ...
    }
)

ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...

вы довольно быстро поймете, что изобретаете колесо в конечном итоге достичь abc.ABCMeta

abc.ABCMeta был предложен в качестве полезного дополнения отсутствующей функциональности интерфейса, и этого достаточно для такого языка, как python.

Конечно, его удалось улучшить при написании версии 3 и добавлении нового синтаксиса и неизменной концепции интерфейса ...

Заключение:

The abc.ABCMeta IS "pythonic" interface in python

Другие вопросы по теме