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

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

6 ответов


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

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 между абстракцией и интерфейсом не существует. Если кто-то попытается определить формальный интерфейс, он также будет абстрактным классом. Единственные различия будут заключаться в заявленном намерении в docstring.

и разница между абстрактным и интерфейсом-это вещь для волос когда у вас есть утка набрав.

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

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


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

поэтому мы обязаны реализовать at меньше __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" определяется как то, что может быть выражено словами. Что мы хотим определить абстрактный базовый класс, который 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!

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

вывод

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


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

абстрактные базовые классы (сокращенно ABCs) дополняют УТК-печатать мимо предоставление способа определения интерфейсов когда другие методы, такие как hasattr() будет топорно. Языка Python поставляется с множество встроенных АБ для структур данных (в модуле коллекции), номера (в модуле numbers) и потоки (в модуле ввода-вывода). Вы можете создать ваш собственный ABC с abc модуль.

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

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


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

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

Python

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


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

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

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


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

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

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