Фреймворк для внедрения зависимостей Python

Есть ли фреймворк, эквивалентный Guice (http://code.google.com/p/google-guice) для Python?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
48
0
34 544
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

Ответ принят как подходящий

Я не использовал его, но фреймворк Весенний Python основан на Spring и реализует Инверсия контроля.

Также, похоже, существует проект Guice in Python: змея

Весенний Python - это ответвление Spring Framework на основе Java и Spring Security, ориентированное на Python. В настоящее время этот проект содержит следующие функции:

  • Инверсия управления (внедрение зависимостей) - используйте либо классический XML, либо декоратор @Object python (аналогичный подпроекту Spring JavaConfig), чтобы связать вещи вместе. Хотя формат @Object не идентичен стилю Guice (централизованная проводка или информация о проводке в каждом классе), это ценный способ связать ваше приложение на Python.
  • Аспектно-ориентированное программирование - применять перехватчики в парадигме горизонтального программирования (вместо вертикального наследования ООП) для таких вещей, как транзакции, безопасность и кеширование.
  • DatabaseTemplate - чтение из базы данных требует монотонного цикла открытия курсоров, чтения строк и закрытия курсоров, а также обработчиков исключений. С этим классом шаблона все, что вам нужно, - это SQL-запрос и функция обработки строк. Остальное сделает Spring Python.
  • Транзакции базы данных - включение нескольких вызовов базы данных в транзакции может затруднить чтение кода. Этот модуль предоставляет несколько способов определения транзакций, не усложняя ситуацию.
  • Безопасность - подключайте перехватчики безопасности, чтобы заблокировать доступ к вашим методам, используя как аутентификацию, так и авторизацию домена.
  • Удаленное взаимодействие - локальное приложение легко преобразовать в распределенное. Если вы уже создали свои клиентские и серверные части, используя контейнер IoC, то переход от локального к распределенному - это всего лишь изменение конфигурации.
  • Примеры - чтобы продемонстрировать различные возможности Spring Python, были созданы несколько примеров приложений:
    • PetClinic - пример веб-приложения Spring Framework был перестроен с нуля с использованием веб-контейнеров Python, включая: CherryPy. Посмотрите, как использовать этот фреймворк. (ПРИМЕЧАНИЕ: другие веб-фреймворки Python будут добавлены в этот список в будущем).
    • Spring Wiki - вики-сайты - это мощные способы хранения и управления контентом, поэтому мы создали простой в качестве демонстрации!
    • Spring Bot - используйте Spring Python для создания крошечного бота для управления IRC-каналом вашего проекта с открытым исходным кодом.

Стоит упомянуть, что SpringPython поддерживает нет Python 3, и он не видел никакой активности с 2014 года ...

canni 14.07.2016 17:43

В качестве альтернативы обезьяньему патчу мне нравится DI. Возникающий проект, такой как http://code.google.com/p/snake-guice/, может соответствовать всем требованиям.

Или посмотрите сообщение в блоге Внедрение зависимостей в Python Денниса Кемпина (август 2008 г.).

Если вы просто хотите выполнить внедрение зависимостей в Python, вам не понадобится фреймворк. Взгляните на Внедрение зависимостей в стиле Python. Это действительно быстро и просто, и только c. 50 строк кода.

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

chiborg 03.05.2011 13:42

Есть какой-то проект Guicey питон-инъекция. Он довольно активен, и кода намного меньше, чем у Spring-python, но, опять же, я еще не нашел причины его использовать.

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

https://github.com/liuggio/Ultra-Lightweight-Dependency-Injector-Python

Это не удобнее, чем создание экземпляров объектов напрямую. Внедрение зависимостей не требует фреймворка.

deamon 29.04.2012 23:44

Вот небольшой пример контейнера внедрения зависимостей, который выполняет внедрение конструктора на основе имен аргументов конструктора:

http://code.activestate.com/recipes/576609-non-invasive-dependency-injection/

Мне нравится этот простой и аккуратный фреймворк.

http://pypi.python.org/pypi/injector/

Dependency injection as a formal pattern is less useful in Python than in other languages, primarily due to its support for keyword arguments, the ease with which objects can be mocked, and its dynamic nature.

That said, a framework for assisting in this process can remove a lot of boiler-plate from larger applications. That's where Injector can help. It automatically and transitively provides keyword arguments with their values. As an added benefit, Injector encourages nicely compartmentalized code through the use of Module s.

While being inspired by Guice, it does not slavishly replicate its API. Providing a Pythonic API trumps faithfulness.

Существует dyject (http://dyject.com), легкий фреймворк для Python 2 и Python 3, который использует встроенный ConfigParser.

pinject (https://github.com/google/pinject) - более новая альтернатива. Кажется, что он поддерживается Google и следует шаблону, аналогичному Guice (https://code.google.com/p/google-guice/), это аналог Java.

Хотя pinject кажется отличным, он не поддерживался годами, и запросы на включение, добавляющие поддержку Python 2.6 и 3.x, оставались открытыми примерно столько же.

David Pärsson 07.09.2016 10:01

Просто к вашему сведению, этот pinject снова кажется активным.

outofthecave 29.06.2020 23:40

Если вам нужен подобный маневр (новый новый, как они говорят), я недавно сделал что-то близкое к Python 3, которое лучше всего соответствовало моим простым потребностям для побочного проекта.

Все, что вам нужно, это @inject для метода (конечно, __init__). Остальное делается с помощью аннотаций.

from py3njection import inject
from some_package import ClassToInject

class Demo:
    @inject
    def __init__(self, object_to_use: ClassToInject):
        self.dependency = object_to_use

demo = Demo()

https://pypi.python.org/pypi/py3njection

Оставлю здесь свои 5 центов :)

https://pypi.python.org/pypi/dependency_injector

"""Pythonic way for Dependency Injection."""

from dependency_injector import providers
from dependency_injector import injections


@providers.DelegatedCallable
def get_user_info(user_id):
    """Return user info."""
    raise NotImplementedError()


@providers.Factory
@injections.inject(get_user_info=get_user_info)
class AuthComponent(object):
    """Some authentication component."""

    def __init__(self, get_user_info):
        """Initializer."""
        self.get_user_info = get_user_info

    def authenticate_user(self, token):
        """Authenticate user by token."""
        user_info = self.get_user_info(user_id=token + '1')
        return user_info


print AuthComponent
print get_user_info


@providers.override(get_user_info)
@providers.DelegatedCallable
def get_user_info(user_id):
    """Return user info."""
    return {'user_id': user_id}


print AuthComponent().authenticate_user(token='abc')
# {'user_id': 'abc1'}

ОБНОВЛЕНО

Прошло некоторое время, и теперь Dependency Injector стал немного другим. Для получения реальных примеров лучше начать со страницы Dependency Injector GitHub - https://github.com/ets-labs/python-dependency-injector

Мне нравится этот ответ, потому что вы дали код. Если у меня будет возможность попробовать, я отдам свой голос.

Mike D 16.06.2017 02:13

Привет @MikeD, спасибо, приятно слышать. Код здесь немного устарел, перейдите по ссылке github.com/ets-labs/python-dependency-injector, чтобы найти актуальный.

Roman Mogylatov 17.06.2017 13:44

Я сделал библиотеку для этого https://github.com/ettoreleandrotognoli/python-cdi Надеюсь, это поможет

Он доступен на pypi: https://pypi.python.org/pypi/pycdi

С его помощью можно делать инъекции с помощью python2

import logging
from logging import Logger

from pycdi import Inject, Singleton, Producer
from pycdi.shortcuts import call


@Producer(str, _context='app_name')
def get_app_name():
    return 'PyCDI'


@Singleton(produce_type=Logger)
@Inject(app_name=str, _context='app_name')
def get_logger(app_name):
    return logging.getLogger(app_name)


@Inject(name=(str, 'app_name'), logger=Logger)
def main(name, logger):
    logger.info('I\'m starting...')
    print('Hello World!!!\nI\'m a example of %s' % name)
    logger.debug('I\'m finishing...')


call(main)

И используя подсказки типа из python3

import logging
from logging import Logger

from pycdi import Inject, Singleton, Producer
from pycdi.shortcuts import call


@Producer(_context='app_name')
def get_app_name() -> str:
    return 'PyCDI'


@Singleton()
@Inject(logger_name='app_name')
def get_logger(logger_name: str) -> Logger:
    return logging.getLogger(logger_name)


@Inject(name='app_name')
def main(name: str, logger: Logger):
    logger.info('I\'m starting...')
    print('Hello World!!!\nI\'m a example of %s' % name)
    logger.debug('I\'m finishing...')


call(main)

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

curveball 06.11.2017 15:00

Я привел несколько примеров, теперь лучше?

Éttore Leandro Tognoli 06.11.2017 16:01

ответ в его форме теперь определенно лучше. Насчет содержания - не могу сказать :)

curveball 06.11.2017 16:15

Хорошо, спасибо! Значит, вы проверяете только, соответствует ли ответ шаблону, а не содержанию?

Éttore Leandro Tognoli 06.11.2017 16:18

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

curveball 06.11.2017 16:43

Я только пытаюсь разобраться в системе, вопрос был очень конкретным "Есть ли фреймворк, эквивалентный Guice (code.google.com/p/google-guice) для Python?" на это могло ответить простое «да». Но я отвечаю: «Я кое-что сделал для этого <<link>>», и этого недостаточно. В то время как ответ типа «Мне нравится этот простой и аккуратный фреймворк. <<link>>» получает 13 голосов. Но неважно, я не буду терять на это больше времени.

Éttore Leandro Tognoli 06.11.2017 17:26

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

curveball 06.11.2017 17:48

Просто прочтите часто задаваемые вопросы, чтобы понять, как должен выглядеть хороший ответ / вопрос. Здесь куча плохих ответов / вопросов. Некоторые из них довольно старые, и с ними обращаются как с наследием. Они закрываются, но не удаляются, поскольку генерируют некоторый трафик (иногда значительный) для сайта. Остальные по-прежнему отображаются, потому что алгоритм их еще не обнаружил. Менеджеры SO на данный момент не хотят превращать SO в ферму ссылок. Здесь у вас есть все инструменты, чтобы дать содержательные ответы. К тому же ссылки как таковые не запрещены - просто дайте немного больше, чем ссылку.

curveball 06.11.2017 17:48

Недавно я выпустил аккуратную (IMHO) микробиблиотеку для DI на python:

https://github.com/suned/serum

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

def foo(dep = None):  # great for unit testing!
    ...

Это чистая инъекция зависимостей (довольно простая), но без волшебных фреймворков для их автоматической инъекции.

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

Под девизом Внедрение зависимости для людей ™ это выглядит так:

# some_service.py
class SomeService:
    @autowired
    def __init__(
        self,
        database: Autowired(Database),
        message_brokers: Autowired(List[Broker]),
    ):
        pending = database.retrieve_pending_messages()
        for broker in message_brokers:
            broker.send_pending(pending)
# database.py
@injectable
class Database:
    ...
# message_broker.py
class MessageBroker(ABC):
    def send_pending(messages):
        ...
# kafka_producer.py
@injectable
class KafkaProducer(MessageBroker):
    ...
# sqs_producer.py
@injectable
class SQSProducer(MessageBroker):
    ...

Enterprython - это небольшой фреймворк, обеспечивающий внедрение зависимостей, автоматически строящий граф объектов на основе подсказки типа.

Я активно разрабатываю Pinject для Python> = 3.6. Использовать довольно просто:

class MyObject:
    my_service: MyService = INJECTED
    my_config: str = INJECTED

Другие вопросы по теме