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






Я не использовал его, но фреймворк Весенний Python основан на Spring и реализует Инверсия контроля.
Также, похоже, существует проект Guice in Python: змея
Кроме того:
Весенний Python - это ответвление Spring Framework на основе Java и Spring Security, ориентированное на Python. В настоящее время этот проект содержит следующие функции:
В качестве альтернативы обезьяньему патчу мне нравится DI. Возникающий проект, такой как http://code.google.com/p/snake-guice/, может соответствовать всем требованиям.
Или посмотрите сообщение в блоге Внедрение зависимостей в Python Денниса Кемпина (август 2008 г.).
Если вы просто хотите выполнить внедрение зависимостей в Python, вам не понадобится фреймворк. Взгляните на Внедрение зависимостей в стиле Python. Это действительно быстро и просто, и только c. 50 строк кода.
Мне не понравилась эта статья, потому что зависимости на самом деле не внедряются, а классы будут зависеть от локатора функций.
Есть какой-то проект Guicey питон-инъекция. Он довольно активен, и кода намного меньше, чем у Spring-python, но, опять же, я еще не нашел причины его использовать.
Если вы предпочитаете действительно крошечное решение, есть небольшая функция, это просто установщик зависимостей.
https://github.com/liuggio/Ultra-Lightweight-Dependency-Injector-Python
Это не удобнее, чем создание экземпляров объектов напрямую. Внедрение зависимостей не требует фреймворка.
Вот небольшой пример контейнера внедрения зависимостей, который выполняет внедрение конструктора на основе имен аргументов конструктора:
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, оставались открытыми примерно столько же.
Просто к вашему сведению, этот pinject снова кажется активным.
Если вам нужен подобный маневр (новый новый, как они говорят), я недавно сделал что-то близкое к 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()
Оставлю здесь свои 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
Мне нравится этот ответ, потому что вы дали код. Если у меня будет возможность попробовать, я отдам свой голос.
Привет @MikeD, спасибо, приятно слышать. Код здесь немного устарел, перейдите по ссылке github.com/ets-labs/python-dependency-injector, чтобы найти актуальный.
Я сделал библиотеку для этого 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)
Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится. - Из обзора
Я привел несколько примеров, теперь лучше?
ответ в его форме теперь определенно лучше. Насчет содержания - не могу сказать :)
Хорошо, спасибо! Значит, вы проверяете только, соответствует ли ответ шаблону, а не содержанию?
Я видел ваш ответ в специальном разделе на этом сайте. Есть инструкции, как написать хороший ответ независимо от содержания - вы можете найти их здесь, на SO. Когда вы публикуете просто ссылку - это не считается хорошим ответом. Вы можете размещать ссылки, но они должны сопровождаться вашими собственными мыслями, комментариями, кодом и т. д.
Я только пытаюсь разобраться в системе, вопрос был очень конкретным "Есть ли фреймворк, эквивалентный Guice (code.google.com/p/google-guice) для Python?" на это могло ответить простое «да». Но я отвечаю: «Я кое-что сделал для этого <<link>>», и этого недостаточно. В то время как ответ типа «Мне нравится этот простой и аккуратный фреймворк. <<link>>» получает 13 голосов. Но неважно, я не буду терять на это больше времени.
Помимо плохих ответов, существуют и плохие вопросы. Также не стоит воспринимать слово «плохой» буквально и лично. «Плохой» ответ / вопрос в этом контексте в основном относится к форматированию, грамматике и логической структуре, а не к самому содержанию. Вы процитировали плохой вопрос.
Просто прочтите часто задаваемые вопросы, чтобы понять, как должен выглядеть хороший ответ / вопрос. Здесь куча плохих ответов / вопросов. Некоторые из них довольно старые, и с ними обращаются как с наследием. Они закрываются, но не удаляются, поскольку генерируют некоторый трафик (иногда значительный) для сайта. Остальные по-прежнему отображаются, потому что алгоритм их еще не обнаружил. Менеджеры SO на данный момент не хотят превращать SO в ферму ссылок. Здесь у вас есть все инструменты, чтобы дать содержательные ответы. К тому же ссылки как таковые не запрещены - просто дайте немного больше, чем ссылку.
Недавно я выпустил аккуратную (IMHO) микробиблиотеку для DI на python:
После нескольких лет использования 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
Стоит упомянуть, что SpringPython поддерживает нет Python 3, и он не видел никакой активности с 2014 года ...