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




7 Answers

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

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

python design-patterns dependency-injection inversion-of-control architecture

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

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

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




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




Я возвращаю ответ «Jörg W Mittag»: «Реализация 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



Я думаю, из-за динамического характера людей-питонов нередко видна необходимость в другой динамической структуре. Когда класс наследуется от нового объекта «объект», вы можете динамически создавать новую переменную ( 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 это может быть то, что вы ищете.

т.е. в 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центы в том, что в большинстве приложений Python вам это не нужно, и даже если вам это нужно, есть вероятность, что многие ненавистники Java (и некомпетентные скрипачи, которые считают разработчиками) считают это чем-то плохим, просто потому, что он популярен в Java ,

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

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

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

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




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

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

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




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

Напомню ( source ):

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






Related