Подтвердить что ты не робот

"Интерфейсы" в Python: да или нет?

Итак, я начинаю проект, используя Python, потратив значительное количество времени на статическую землю. Я видел некоторые проекты, которые создают "интерфейсы", которые на самом деле являются просто классами без каких-либо реализаций. Раньше я издевался над этой идеей и игнорировал эту часть этих проектов. Но теперь я начинаю согреваться до этой идеи.

Просто так, мы понятны, интерфейс в Python будет выглядеть примерно так:

class ISomething(object):
    def some_method():
        pass
    def some_other_method(some_argument):
        pass

Обратите внимание, что вы не передаете себя ни одному из методов, тем самым требуя, чтобы метод был переопределен для вызова. Я рассматриваю это как хорошую форму документации и полноте тестирования.

Итак, что же здесь такое мнение по этой идее? Могу ли я промыть мозги всем программированием на С#, которое я сделал, или это хорошая идея?

4b9b3361

Ответ 1

В некоторых случаях интерфейсы могут быть очень удобными. Twisted делает довольно широкое использование интерфейсы Zope, и в проекте, над которым я работал, интерфейсы Zope работали очень хорошо. Недавно появившиеся черты enthought добавили интерфейсы, но у меня нет опыта с ними.

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

Ответ 2

Я не уверен, в чем дело. Интерфейсы (такой формы, во всяком случае) в значительной степени работают вокруг отсутствия множественного наследования. Но у Python есть MI, так почему бы просто не сделать абстрактный класс?

class Something(object):
    def some_method(self):
        raise NotImplementedError()
    def some_other_method(self, some_argument):
        raise NotImplementedError()

Ответ 3

В Python 2.6 и более поздних версиях вместо этого можно использовать абстрактные базовые классы. Они полезны, потому что затем вы можете проверить, что-то реализует данный ABC, используя "isinstance". Как обычно в Python, концепция не так строго соблюдалась, как это было бы на строгом языке, но это было бы удобно. Кроме того, есть хорошие идиоматические способы объявления абстрактных методов с помощью декораторов - см. Ссылку выше для примеров.

Ответ 4

Питонический путь - "Просить прощения, а не получать разрешения". Интерфейсы связаны с получением разрешения на выполнение некоторой операции над объектом. Python предпочитает это:

def quacker(duck):
    try:
        duck.quack():
    except AttributeError:
        raise ThisAintADuckException

Ответ 5

Я не думаю, что интерфейсы ничего не добавили бы в среду кода.

  • Применение определения метода происходит без них. Если объект, который, как ожидается, будет иметь Foo и имеет метод bar(), и он не будет, он выкинет AttributeError.
  • Просто убедитесь, что метод интерфейса определен, не гарантирует его правильность; в любом случае должны проводиться тесты на основе поведения.
  • Так же эффективно писать страницу "прочитать это или умереть", описывая, какие методы должен иметь ваш объект, чтобы быть совместимым с тем, что вы подключаете к нему, поскольку у вас есть сложные docstrings в классе интерфейса, поскольку вы, вероятно, в любом случае, для этого есть тесты. Один из этих тестов может быть стандартным для всех совместимых объектов, которые будут проверять тип вызова и возврата для каждого базового метода.

Ответ 6

Мне кажется ненужным - когда я пишу такие классы, я обычно просто делаю базовый класс (ваш ISomething) без методов и упоминаю в фактической документации, какие подклассы методов должны переопределяться.

Ответ 7

Вы можете создать интерфейс на динамически типизированном языке, но при компиляции не будет применен интерфейс. Компилятор статически типизированного языка предупредит вас, если вы забудете реализовать (или ввести в заблуждение!) Метод интерфейса. Поскольку вы не получаете такой помощи на динамически типизированном языке, ваша декларация интерфейса служит только как документация. (Что не обязательно плохо, просто так, что декларация интерфейса не обеспечивает преимущества во время выполнения и написания комментариев.)

Ответ 8

Я собираюсь сделать что-то подобное с моим проектом Python, единственное, что я добавил бы:

  • Дополнительные длинные строки для каждого интерфейса и все абстрактные методы.
  • Я бы добавил все необходимые аргументы, чтобы там был окончательный список.
  • Поднять исключение вместо 'pass'.
  • Префикс всех методов, поэтому они, очевидно, являются частью интерфейса - интерфейс Foo: def foo_method1()

Ответ 9

Я лично очень часто использую интерфейсы в сочетании с Zope Component Architecture (ZCA). Преимущество состоит не столько в том, чтобы иметь интерфейсы, сколько в том, чтобы использовать их с адаптерами и утилитами (одиночные игры).

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

Первоначальный класс:

class MyClass(object):
  implements(ISomething)

  def do_something(self):
      return "foo"

Тогда представьте интерфейс ISomethingElse имеет метод do_something_else(). Адаптер может выглядеть так:

class SomethingElseAdapter(object):
    implements(ISomethingElse)
    adapts(ISomething)

    def __init__(self, context):
        self.context = context

    def do_something_else():
        return self.context.do_something()+"bar"

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

>>> obj = MyClass()
>>> print obj.do_something()
"foo"
>>> adapter = ISomethingElse(obj)
>>> print adapter.do_something_else()
"foobar"

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

Это, конечно, в основном полезно для фреймворков/библиотек.

Я думаю, что для того, чтобы привыкнуть к нему, требуется некоторое время, но я больше не хочу жить без него. Но, как сказано выше, также верно, что вам нужно точно подумать, где это имеет смысл, а где нет. Разумеется, интерфейсы на нем тоже могут быть полезны в качестве документации API. Это также полезно для модульных тестов, где вы можете проверить, действительно ли ваш класс реализует этот интерфейс. И последнее, но не в последнюю очередь мне нравится начинать с написания интерфейса и некоторых доктрин, чтобы получить представление о том, что я на самом деле собираюсь закодировать.

Для получения дополнительной информации вы можете проверить мое небольшое введение в него и есть довольно подробное описание этого API.

Ответ 11

Вы посмотрели PyProtocols? у него есть хорошая реализация интерфейса, на которую вы должны смотреть.