Почему IoC / DI не распространены в Python?


313

В Java IoC / DI является очень распространенной практикой, которая широко используется в веб-приложениях, почти во всех доступных средах и Java EE. С другой стороны, есть также много больших веб-приложений на Python, но помимо Zope (который, как я слышал, должно быть ужасно кодировать), IoC, похоже, не очень распространен в мире Python. (Пожалуйста, назовите несколько примеров, если вы считаете, что я ошибаюсь).

Конечно, есть несколько клонов популярных фреймворков Java IoC, доступных для Python, например , Springpython . Но никто из них, кажется, не привык практически. По крайней мере, я никогда не сталкивался с веб-приложением на основе Django или sqlalchemy +, <insert your favorite wsgi toolkit here>которое использует что-то подобное.

На мой взгляд, IoC имеет разумные преимущества и позволит легко заменить django-default-user-model, например, но широкое использование классов интерфейса и IoC в Python выглядит немного странно, а не «pythonic». Но, возможно, у кого-то есть лучшее объяснение, почему IoC не широко используется в Python.


2
Полагаю, по той же причине, что он менее популярен в Ruby, встроенных миксинах и открытых классах
Сэм Саффрон

3
Вы когда-нибудь пробовали Springpython? это даже не работает как рекламируется. по крайней мере, в aop части. все остальное там не очень полезно, если вы не приехали из Java и не нуждаетесь в некотором уровне комфорта во время перехода.
Том Уиллис

6
Пожалуйста, позаботьтесь о том, чтобы различать использование DI и использование инфраструктуры IOC. Первый - это шаблон проектирования, последний - это структура, помогающая автоматизировать использование первого.
Дуг

Даг, я полагаю, вы хотели сказать, что DI - это творческая особенность, которая получается с помощью шаблона Decorator.
njappboy

4
Мне бы очень хотелось получить ответ, который решает проблемы реального мира, которые решает DI: управление временем жизни, простота озвучивания тестов и т. Д. Если есть более питонский способ решения этих проблем, я весь в ушах.
Джош Ноу

Ответы:


197

Я на самом деле не думаю , что DI / IoC являются , что редкость в Python. Что является необычным, однако, DI / IoC каркасы / контейнеры .

Подумайте об этом: что делает контейнер DI? Это позволяет вам

  1. объединить независимые компоненты в единое приложение ...
  2. ... во время выполнения.

У нас есть имена для «соединения вместе» и «во время выполнения»:

  1. скриптовый
  2. динамический

Таким образом, контейнер DI - это не что иное, как интерпретатор динамического языка сценариев. На самом деле, позвольте мне перефразировать это: типичный контейнер Java / .NET DI - не что иное, как дурацкий интерпретатор для действительно плохого языка динамических сценариев с непривлекательным, иногда основанным на XML, синтаксисом.

Когда вы программируете на Python, зачем вам использовать уродливый, плохой язык сценариев, когда в вашем распоряжении прекрасный, блестящий язык сценариев? На самом деле, это более общий вопрос: когда вы программируете практически на любом языке, зачем вам использовать уродливый, плохой язык сценариев, когда у вас есть Jython и IronPython?

Итак, подведем итог: практика использования DI / IoC в Python так же важна, как и в Java, по тем же причинам. реализация DI / IoC встроена в язык и часто настолько легка, что полностью исчезает.

(Вот краткое замечание для аналогии: в ассемблере вызов подпрограммы является довольно серьезной проблемой - вы должны сохранить свои локальные переменные и регистры в памяти, где-то сохранить свой обратный адрес, изменить указатель инструкции на вызываемую подпрограмму, сделайте так, чтобы он каким-то образом возвращался в вашу подпрограмму после ее завершения, помещал аргументы куда-то, где вызываемый может их найти, и т. д. IOW: в сборке «вызов подпрограммы» является шаблоном проектирования, и до того, как появились такие языки, как Fortran, в котором были встроены вызовы подпрограмм, люди строили свои собственные "структуры подпрограмм". Вы бы сказали, что вызовы подпрограмм "необычны" в Python, просто потому, что вы не используете структуры подпрограмм?)

BTW: для примера того , что он выглядит как взять DI к своему логическому завершению, взгляните на Гилада Браха «s новояза Язык программирования и его труды по этой теме:


58
Пока я согласен. Комментарий XML неверен. Многие (по крайней мере, современные) контейнеры IOC используют соглашение (код) поверх конфигурации (XML).
Finglas

20
Ничто не мешает вам писать в явном виде в Java, но по мере того, как у вас появляется все больше и больше сервисов, зависимости становятся более сложными. Контейнер DI похож на Make: вы объявляете зависимости, и контейнер инициализирует их в правильном порядке. Guice - это инфраструктура Java DI, где все написано в коде Java. При декларативном написании контейнера DI также добавляется поддержка постобработки деклараций перед инициализацией (например, замена заполнителей свойств фактическими значениями)
IttayD

133
«Однако реализация DI / IoC встроена в язык и часто настолько легка, что полностью исчезает». Голосуйте против, потому что это категорически неверно. DI - это шаблон, в котором интерфейс передается в конструктор. Он не встроен в Python.
Дуг

146
downvote, проводка вместе не имеет ничего общего со сценариями, DI - это шаблон, и он не эквивалентен сценариям
Luxspes

38
Я не согласен с этим. DI не решает проблему отсутствия динамических сценариев в статических языках. Он обеспечивает основу для настройки и составления частей вашего приложения. Однажды я слышал, как разработчик Ruby сказал, что DI не нужен в динамических языках. Но он использовал Rails ... Rails - это просто большой DI-контейнер, который использует соглашение, чтобы выяснить, какие части настраивать, когда. Он не нуждался в DI, потому что Rails решил проблему с поиском запчастей для него.
Брайан Дженисио

51

Отчасти это то, как система модулей работает в Python. Вы можете получить своего рода «синглтон» бесплатно, просто импортировав его из модуля. Определите фактический экземпляр объекта в модуле, и тогда любой клиентский код может импортировать его и фактически получить работающий, полностью построенный / заполненный объект.

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


2
В этом есть смысл. Если я хочу изменить реализацию в Python, я просто импортирую из другого места с тем же именем. Но теперь я думаю, возможно ли и наоборот, определив MyClassInstancesкласс для каждого MyClassв Java, который содержит только статические, полностью инициализированные экземпляры. Это будет проводной: D
tux21b

2
И еще одна идея: предоставление способа изменения такого импорта в python позволит легко заменить реализации, не затрагивая все файлы python. Вместо from framework.auth.user import User этого может быть лучше написать User = lookup('UserImplentation', 'framework.auth.user.User')(2-й параметр может быть значением по умолчанию) внутри фреймворка. Тогда пользователи фреймворка смогут заменить / специализировать Userреализацию, не касаясь фреймворка.
tux21b

14
Упрощенно, ответьте, в реальной жизни вам редко нужен просто «синглтон», вам нужно контролировать область (вам может понадобиться локальный синглтон потока или синглтон сеанса и т. Д.), Это заставляет меня думать, что проблемы такого рода решаемые в Python не являются проблемами реального мира, которые на самом деле решаются на предприятии
Luxspes

3
На самом деле DI - это возможность тестировать и отделять зависимости кода. Также функция импорта аналогична статическому импорту в Java, что позволяет мне импортировать один экземпляр объекта.
Ричард Уорбертон

1
«Вы можете получить своего рода« синглтон »бесплатно, просто импортировав его из модуля.» Это можно легко сделать в Java, объявив поле статического экземпляра и установив его значение. Это не sol
ggranum

45

IoC и DI очень распространены в зрелом коде Python. Вам просто не нужен каркас для реализации DI, благодаря утилитному типу.

Лучший пример - как настроить приложение Django, используя settings.py:

# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': REDIS_URL + '/1',
    },
    'local': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'snowflake',
    }
}

Django Rest Framework активно использует DI:

class FooView(APIView):
    # The "injected" dependencies:
    permission_classes = (IsAuthenticated, )
    throttle_classes = (ScopedRateThrottle, )
    parser_classes = (parsers.FormParser, parsers.JSONParser, parsers.MultiPartParser)
    renderer_classes = (renderers.JSONRenderer,)

    def get(self, request, *args, **kwargs):
        pass

    def post(self, request, *args, **kwargs):
        pass

Напомню ( источник ):

«Инъекция зависимости» - это понятие за 5 центов стоимостью 25 долларов. [...] Внедрение зависимости означает предоставление объекту его переменных экземпляра. [...].


8
+1. Хорошо сказано. Будучи программистом на Python, я был совершенно сбит с толку целой презентацией интервью по DI-фреймворкам в C #. Мне потребовалось некоторое время, чтобы понять, что я уже делал это все время в приложениях Flask, даже не задумываясь об этом, потому что вам не нужна инфраструктура. Для кого-то, кто не знает ничего кроме C # / Java, вопрос имеет смысл. Для программистов, использующих утку, это естественно и, как вы говорите, «25-долларовый термин для концепции 5 центов».
Самюэль Хармер

5
эээ ... это не внедрение зависимостей, так как экземпляры ( IsAuthenticated, ScopedRateThrottle) создаются классом. Они не передаются в конструктор.
Допатраман

5
IsAuthenticatedи ScopedRateThrottleне экземпляры, это классы. Они создаются при создании FooView (фактически, когда FooView обрабатывает запрос). В любом случае, это просто деталь реализации. IsAuthenticatedи ScopedRateThrottleявляются зависимостями; они вводятся в FooView. Неважно, когда и как это делается. Python не является Java, поэтому есть разные способы реализовать это.
Макс Малыш

3
@MaxMalysh Я согласен с допатраман в этом. Это даже не IoC, поскольку сам класс имеет «жестко закодированные» зависимости от конкретного класса. В IoC зависимость должна предоставляться вместо жестко закодированной. Вдобавок ко всему, в Dependency Injection у вас будет организация, отвечающая за управление жизненными циклами каждой службы и внедрение их в этом случае. Решение предусмотрено ни в одном из них.
Рикардо Алвес

3
@alex Нет, вам не нужно менять код, чтобы использовать другой рендерер. Вы даже можете использовать несколько рендеров одновременно renderer_classes = (JSONRenderer, BrowsableAPIRenderer, XMLRenderer). Дразнить так же просто, как @unittest.patch('myapp.views.FooView.permission_classes'). Отчаянная необходимость «передавать что-то» является следствием «способа выполнения действий на Java», поскольку Java является скомпилированным и статически типизированным языком, в котором отсутствуют сильные возможности метапрограммирования.
Макс Малыш

35

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

Разница в том, что Python имеет первоклассные типы. Типы данных, включая классы, сами являются объектами. Если вы хотите, чтобы что-то использовало определенный класс, просто назовите класс. Например:

if config_dbms_name == 'postgresql':
    import psycopg
    self.database_interface = psycopg
elif config_dbms_name == 'mysql':
    ...

Более поздний код может затем создать интерфейс базы данных, написав:

my_db_connection = self.database_interface()
# Do stuff with database.

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


4
То, что вы называете кодом, на самом деле является частью проводки. Это будет XML вашего ioc фреймворка. На самом деле это может быть написано просто как import psycopg2 as database_interface. Поместите эту строку в injections.pyet voilà.
спектры

29
Эмм. То, что ты делаешь там, в значительной степени является обязательным требованием к учебнику, Даниэль
Шейн

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

5
Разве это не просто функции первого класса? en.wikipedia.org/wiki/First-class_function Только то, что вы их используете и используете, не делает ваш код функциональным. Здесь происходит довольно много побочных эффектов (таких как изменение self.database_interface), которые крайне необходимы.
hjc1710

15

Он видит, что люди больше не понимают, что означает внедрение зависимостей и инверсия управления.

Практика использования инверсии управления состоит в том, чтобы иметь классы или функции, которые зависят от других классов или функций, но вместо создания экземпляров, в которых находится класс функционального кода, лучше получить его в качестве параметра, поэтому слабая связь может быть заархивирована. Это имеет много преимуществ, таких как большая тестируемость и возможность замещения принципа замены Лискова.

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

Для чего нужна библиотека DI, если вы можете создать экземпляр объекта внутри пакета и импортировать его, чтобы внедрить его самостоятельно? Выбранный ответ правильный, так как в Java нет процедурных разделов (код вне классов), все, что входит в скучные XML-файлы конфигурации, и, следовательно, необходимость класса для создания и вставки зависимостей в режиме ленивой загрузки, чтобы вы не сдували ваша производительность, в то время как на python вы просто кодируете инъекции в «процедурные» (код вне классов) вашего кода


вам все еще не хватает того, что IoC / DI автоматически соединяет объекты. Это не так много возможности сделать это во время выполнения (в любом случае Java может сделать это с помощью отражения), это то, что фреймворк заботится об этом, и вам не нужно делать это явно. Наличие процедурных разделов также не имеет значения, ничто не мешает написать полностью процедурное приложение на Java, используя классы как простые контейнеры статических подпрограмм и функций, вообще не используя функции ООП.
Закмк

@zakmck: «процедурный» раздел Python на самом деле не о написании процедурного кода. Что делает «процедурный» раздел Python отличным от статических языков, так это возможность помещать процедурный код в тело класса, которое выполняется во время определения класса, и помещать операторы импорта внутри оператора if, и создавать фабрику классов просто путем определения классов внутри фабричного метода. Это вещи, которые вы не можете сделать на статических языках, и которые решают большинство проблем, которые пытались решить IOC / DI. Метапрограммирование в Python часто выглядит как обычный код Python.
Ли Райан

@LieRyan, вы можете сделать это с помощью отражения, или, если вам это нужно часто или во время выполнения, вы можете вызвать статический язык из другого языка, такого как Groovy (который предназначен для простой игры с Java), или даже самого Python. Тем не менее, это не имеет ничего общего с инфраструктурами IoC / DI, поскольку их целью является автоматическое выполнение большей части процедурной разводки объектов, используя только определения. К сожалению, большинство настоящих ответов упускают этот момент.
Закмк

12

Python не использовался несколько лет, но я бы сказал, что он больше связан с тем, что он является языком с динамической типизацией, чем с чем-либо еще. Для простого примера, в Java, если бы я хотел проверить, что-то записано в соответствии со стандартом, я мог бы использовать DI и передать любой PrintStream, чтобы захватить записываемый текст и проверить его. Тем не менее, когда я работаю в Ruby, я могу динамически заменять метод «put» на STDOUT для проверки, оставляя DI полностью вне поля зрения. Если единственной причиной, по которой я создаю абстракцию, является тестирование класса, который ее использует (например, операции файловой системы или часы в Java), то DI / IoC создает ненужную сложность в решении.


3
Меня не перестает удивлять тот факт, что люди хотят изменить работу системы, чтобы проверить, работает ли она. Теперь вам нужно проверить, что ваши тесты не вызывают побочных эффектов.
Базовая

2
он говорит об изменении метода put только в области тестов, это похоже на фиктивный метод внедренного объекта.
ДП

2
@Basic, что вполне нормально в модульных тестах , на самом деле это целесообразно делать в этих тестах, поскольку вы не хотите загрязнять покрытие тестового набора более чем одним блоком кода (который тестируется). Было бы неправильно делать это для интеграционных тестов, хотя, может быть, это то, на что вы ссылаетесь в своем комментарии?
Самуэльгриголато

1
Для меня тестируемость - первостепенная задача. Если дизайн не поддается тестированию, это не очень хороший дизайн, и у меня нет проблем с изменением дизайна, чтобы сделать его более тестируемым. Я должен подтвердить, что это все еще работает, но это нормально. Тестируемость - совершенно веская причина для изменения кода ИМО
Карлос Родригес

10

На самом деле, довольно просто написать достаточно чистый и компактный код с помощью DI (интересно, будет ли он / останется тогда пифоническим , но в любом случае :)), например, я на самом деле предпочитаю такой способ кодирования:

def polite(name_str):
    return "dear " + name_str

def rude(name_str):
    return name_str + ", you, moron"

def greet(name_str, call=polite):
    print "Hello, " + call(name_str) + "!"

_

>>greet("Peter")
Hello, dear Peter!
>>greet("Jack", rude)
Hello, Jack, you, moron!

Да, это можно рассматривать как простую форму параметризации функций / классов, но это делает свою работу. Так что, может быть, батарейки Python, включенные по умолчанию, здесь тоже достаточно.

PS Я также опубликовал более крупный пример этого наивного подхода в разделе Динамическая оценка простой логической логики в Python .


3
Для простых случаев, которые могут работать, но просто представьте себе простой контроллер веб-блога, который использует различные модели (Post, Comment, User). Если вы хотите, чтобы пользователь ввел свою собственную модель Post (с дополнительным атрибутом viewcount, чтобы отслеживать это), и свою собственную модель User с дополнительной информацией профиля и т. Д., Все параметры могут выглядеть запутанными. Кроме того, пользователь может также захотеть изменить объект Request, чтобы поддерживать сеанс файловой системы вместо простого сеанса на основе файлов cookie или чего-то в этом роде ... Итак, вскоре вы получите множество параметров.
tux21b

1
@ tux21b Ну, есть «существенная сложность», которую пользователи хотят реализовать в приложении, есть архитектурные решения (некоторые из которых не хуже остальных с точки зрения разработки и, возможно, времени обслуживания, скорости исполнения и т. д.). ), и есть человеческая способность понимать API и архитектуру программного обеспечения. Если вообще не существует приемлемого для человека решения (не только среди тех, кто использует (любую форму) DI) ... ну, кто сказал, что все проблемы разрешимы? И наличия множества назначенных по умолчанию (но заменяемых по выбору пользователя) параметров может быть достаточно часто.
млвлйр

9

IoC / DI - это концепция дизайна, но, к сожалению, ее часто принимают за концепцию, которая применяется к определенным языкам (или системам ввода). Я бы хотел, чтобы контейнеры для инъекций зависимостей стали намного популярнее в Python. Есть Spring, но это супер-фреймворк, и он, кажется, является прямым портом концепций Java без особого рассмотрения «Пути Python».

Учитывая аннотации в Python 3, я решил взломать полнофункциональный, но простой контейнер внедрения зависимостей: https://github.com/zsims/dic . Он основан на некоторых концепциях из контейнера для внедрения зависимостей .NET (что является ИМО фантастическим, если вы когда-либо играете в этом пространстве), но мутирует с концепциями Python.


6

Я думаю, что из-за динамической природы Python люди не часто видят необходимость в другой динамической среде. Когда класс наследует от «объекта» нового стиля, вы можете динамически создать новую переменную ( https://wiki.python.org/moin/NewClassVsClassicClass ).

т.е. в простом питоне:

#application.py
class Application(object):
    def __init__(self):
        pass

#main.py
Application.postgres_connection = PostgresConnection()

#other.py
postgres_connection = Application.postgres_connection
db_data = postgres_connection.fetchone()

Однако взгляните на https://github.com/noodleflake/pyioc это может быть то, что вы ищете.

то есть в пиок

from libs.service_locator import ServiceLocator

#main.py
ServiceLocator.register(PostgresConnection)

#other.py
postgres_connection = ServiceLocator.resolve(PostgresConnection)
db_data = postgres_connection.fetchone()

2
Тот факт, что обе версии занимают одинаковое количество кода, в значительной степени объясняет, почему использование фреймворка не очень популярно.
спектры

В other.pyстроке 1 есть автоматическое разрешение зависимостей, но оно не будет учитываться как внедрение зависимостей.
andho

Сервисные локаторы - это, как правило, анти-паттерн.
PmanAce

6

Я возвращаюсь к ответу «Йорг Миттаг»: «Реализация DI / IoC на Python настолько легка, что полностью исчезает».

Чтобы поддержать это утверждение, взгляните на знаменитый пример Мартина Фаулера, портированный с Java на Python: Python: Design_Patterns: Inversion_of_Control

Как видно из приведенной выше ссылки, «Контейнер» в Python может быть записан в 8 строках кода:

class Container:
    def __init__(self, system_data):
        for component_name, component_class, component_args in system_data:
            if type(component_class) == types.ClassType:
                args = [self.__dict__[arg] for arg in component_args]
                self.__dict__[component_name] = component_class(*args)
            else:
                self.__dict__[component_name] = component_class

42
Это далеко не соответствует даже самым слабым контейнерам DI. Где управление жизненным циклом, рекурсивное разрешение зависимостей, возможность имитировать или, если не все, конфигурация? Это не что иное, как поиск типов и кеш, что не то же самое, что IoC.
Базовая

2
Несколько лет назад я написал небольшую структуру DI, используя метаклассы в качестве упражнения. Все это один файл с нулевым импортом и тестами, что делает его самоочевидным. Это показывает, что базовые функции не так сложно реализовать, даже если они «питонны», но я искренне думаю, что грустно, что ни одно законченное решение не получило такого большого преимущества, как Spring в Java, и каждый занимается созданием пользовательских архитектур плагинов.
Андреа Ратто

2

Мой 2cents заключается в том, что в большинстве приложений Python он вам не нужен, и даже если вам это нужно, есть вероятность, что многие ненавистники Java (и некомпетентные фиддлеры, которые считают себя разработчиками) считают это чем-то плохим, просто потому, что он популярен в Java ,

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

Типичное приложение Python намного проще, просто набор сценариев, без такой сложной архитектуры. Лично я знаю, что такое IoC (в отличие от тех, кто написал определенные ответы здесь), и я никогда не чувствовал необходимости в этом из-за моего ограниченного опыта работы с Python (также я не использую Spring везде, не когда преимущества это не оправдывает его развитие).

Тем не менее, существуют ситуации Python, где подход IoC действительно полезен, и, на самом деле, я читал здесь, что Django использует его.

Те же рассуждения, приведенные выше, могут быть применены к аспектно-ориентированному программированию в мире Java, с той разницей, что число случаев, когда AOP действительно стоит, еще более ограничено.


Есть ли ссылка на источник информации, где django использует IoC?
Саджук

@Sajuuk, я узнал это о Django в ветке этого вопроса, так что я не знаю, вы должны спросить других авторов ответа.
Закмк

Первая алинея этого ответа добавляет 0 значение по моему мнению ... Я думаю, что я могу решить, когда мой код на Python выиграет от IoC, и мне все равно, что разработчик считает плохим. Я ценю прагматизм, а не необоснованные мнения.
Майк де Клерк

@MikedeKlerk Мое предложение состоит в том, что что-то, что является одновременно и неизвестным (что подтверждается многими ответами), и жертвой предубеждения, вряд ли станет популярным, независимо от того, насколько объективны и хорошо осведомлены такие, как вы. И, конечно, я не уверен, что это причина того, что вы не видите много использования IoC в Python, я думаю, что основная причина в том, что приложения с низкой / средней конкуренцией не нуждаются в них.
zakmck

The typical Python application is much simpler, just a bunch of scripts, without such a complex architecture.- довольно предположение
Гянков


-1

Я согласен с @Jorg в том, что DI / IoC возможен, проще и еще красивее в Python. Чего не хватает, так это фреймворков, поддерживающих его, но есть несколько исключений. Чтобы привести пару примеров, которые приходят мне в голову:

  • Комментарии Django позволяют вам связать свой собственный класс Comment с вашей собственной логикой и формами. [Больше информации]

  • Django позволяет использовать пользовательский объект профиля для присоединения к вашей модели пользователя. Это не совсем IoC, но это хороший подход. Лично я хотел бы заменить дырочную модель пользователя, как это делает структура комментариев. [Больше информации]


-3

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

Это также признак статически типизированного языка. Когда единственным средством выражения абстракции является наследование, это то, что вы используете везде. Сказав это, C ++ очень похож, но никогда не привлекал внимание везде, где это делали разработчики Java, с Builders и Interfaces. Легко стать чрезмерно обильным с мечтой быть гибким и расширяемым за счет написания слишком большого количества общего кода с небольшой реальной выгодой . Я думаю, что это культурная вещь.

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


4
Это не столько рамки, сколько сам язык. Для создания гибкости, которой обладают языки утиной типизации, статически типизированные языки нуждаются в очень сложных основах и правилах. Д.И. является одним из тех правил. Python люди не думают дважды о. Java люди должны действительно работать над этим.
S.Lott

6
@ S.Lott - Я бы полностью с вами согласился, за исключением того, что люди на C ++, кажется, обходятся без взрыва шаблонов проектирования и архитектуры, несмотря на то, что работают с аналогичными ограничениями, что и в Java. Я думаю, что это подразумевает культурную разницу, когда, столкнувшись с двумя возможными способами сделать что-то, Java-люди предпочитают извлекать другой интерфейс для упрощения шаблона Стратегии, тогда как C ++ люди погружаются прямо в него и добавляют bool и оператор if ...
Килотан

3
@Finglas, поэтому, если у меня есть дюжина классов, использующих мои, EmailSenderи я решу заменить их на a DesktopNotifier, я должен отредактировать 12 классов вручную. И вы думаете, что это проще и чище, чем просто писать в INotifierинтерфейс и позволить контейнеру проработать детали?
Базовая

1
К сожалению, определенный уровень сложности - это реальность, с которой сталкиваются профессиональные разработчики программного обеспечения. Я вижу критику, но нет решений в этом ответе. Что такое «питоническое» решение этой проблемы: я пишу библиотеку и хочу предоставить хук для ведения журнала (что-то вроде PHP PSR-3 LoggerInterface). Я знаю, как использовать уровни журналов, но мне все равно, как программа на самом деле сообщает о них. Как правильно разрешить клиентскому приложению внедрять детали реализации? Примечание: другие части приложения могут иметь разные реализации этого интерфейса.
Роб

2
Мой вопрос к вам не о том, как вы используете стандартную библиотеку журналов, и не о создании разных экземпляров класса регистратора. Мой вопрос заключается в том, как настроить приложение так, чтобы разные части приложения могли использовать разные реализации и не заботиться об этих деталях (при условии, что они знают, как использовать интерфейс). Это очень реальная проблема, которую DI решил для нескольких приложений PHP, над которыми я работал. Я ищу эквивалент Python. И предложение «просто не делайте ваше приложение таким сложным» - это не тот ответ, который я ищу.
Роб

-5

В отличие от строго типизированной природы в Java. Поведение Python по типу "утка" позволяет легко передавать объекты.

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

Разработчики Python сосредоточены на выполнении работы. Они просто подключают классы, когда им это нужно. Им даже не нужно беспокоиться о типе класса. Пока это может крякать, это утка! Эта природа не оставляет места для IoC.


4
Вам все еще нужно найти вещь, которая крякает.
andho
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.