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


Answers

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

Разница в том, что 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 делает это с одной или двумя строками обычного кода. Это сила функционального и императивного программирования.

Question

В 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.




Я возвращаю ответ «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



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

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

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




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



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

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

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




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




Links