Разница между абстрактным классом и интерфейсом в Python - PullRequest
505 голосов
/ 16 декабря 2008

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

Ответы [ 6 ]

573 голосов
/ 16 декабря 2008

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

class Abstract1( object ):
    """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( object ):
    pass # lots of stuff - but missing something

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

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

class Concrete1( SomeAbstraction, Mixin1 ):
    pass

class Concrete2( SomeAbstraction, Mixin2 ):
    pass

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

162 голосов
/ 15 июля 2015

В чем разница между абстрактным классом и интерфейсом в 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

Например, «выполнимый» определяется как нечто, что можно выразить словами. Скажем, мы хотели определить абстрактный базовый класс, который является эффективным, в 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.

99 голосов
/ 16 декабря 2008

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

Абстрактные базовые классы (сокращенно Азбука) дополняют типизацию предоставляя способ определения интерфейсов когда другие методы, такие как hasattr () было бы неуклюже Python поставляется с много встроенных ABC для структур данных (в модуле коллекций), номера (в модуле номеров) и потоки (в модуле io). Вы можете создать ваш собственный ABC с модулем abc.

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

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

37 голосов
/ 16 декабря 2008

Python на самом деле не имеет ни одной концепции.

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

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

Python> = 2.6: Абстрактные базовые классы существуют (http://docs.python.org/library/abc.html). и позволяют указывать методы, которые должны быть реализованы в подклассах. Мне не очень нравится синтаксис, но функция есть. Большую часть времени вероятно, лучше использовать утку с клиентской стороны "using".

29 голосов
/ 08 мая 2013

Более простым способом объяснить: Интерфейс похож на пустую форму для кексов. Это файл класса с набором определений методов, которые не имеют кода.

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

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

15 голосов
/ 16 декабря 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...