【问题标题】:Python Dependency Injection FrameworkPython 依赖注入框架
【发布时间】:2010-09-14 10:46:21
【问题描述】:

是否有与 Python 的 Guice (http://code.google.com/p/google-guice) 等效的框架?

【问题讨论】:

    标签: python dependency-injection


    【解决方案1】:

    Spring Python 是基于 Java 的 Spring Framework 和 Spring Security 的一个分支,面向 ​​Python。该项目目前包含以下功能:

    • Inversion Of Control (dependency injection) - 使用经典 XML 或 python @Object 装饰器(类似于 Spring JavaConfig 子项目)将事物连接在一起。虽然@Object 格式与 Guice 样式不同(集中连接与每个类中的连接信息),但它是连接 Python 应用程序的一种有价值的方式。
    • Aspect-oriented Programming - 在横向编程范式(而不是纵向 OOP 继承)中应用拦截器来处理事务、安全性和缓存等事务。
    • DatabaseTemplate - 从数据库读取需要打开游标、读取行和关闭游标的单调循环,以及异常处理程序。使用这个模板类,您只需要 SQL 查询和行处理功能。 Spring Python 完成了剩下的工作。
    • 数据库事务 - 使用事务包装多个数据库调用会使您的代码难以阅读。该模块提供了多种方法来定义事务,而不会使事情变得复杂。
    • 安全性 - 使用身份验证和域授权来锁定对您的方法的访问的插件安全拦截器。
    • 远程处理 - 将本地应用程序转换为分布式应用程序很容易。如果您已经使用 IoC 容器构建了客户端和服务器部分,那么从本地到分布式只是一个配置更改。
    • 示例 - 为了帮助演示 Spring Python 的各种功能,创建了一些示例应用程序:
      • PetClinic - Spring Framework 的示例 Web 应用程序已使用 python Web 容器从头开始重建,包括:CherryPy。去看看如何使用这个框架的例子。 (注意:其他 python web 框架将来会添加到这个列表中)。
      • Spring Wiki - Wiki 是存储和管理内容的强大方式,因此我们创建了一个简单的演示版!
      • Spring Bot - 使用 Spring Python 构建一个微型机器人来管理您的开源项目的 IRC 通道。

    【讨论】:

    • 值得一提的是,SpringPython 确实支持 Python 3,并且自 2014 年以来没有任何活动......
    【解决方案2】:

    我喜欢这个简单整洁的框架。

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

    依赖注入作为一种正式模式在 Python 中的用处不如 在其他语言中,主要是因为它支持关键字 论点,对象可以被模拟的难易程度,以及它的动态性 自然。

    也就是说,协助这个过程的框架可以消除很多 来自较大应用的样板。这就是注射器可以的地方 帮助。它自动和传递地提供关键字参数 与他们的价值观。作为一个额外的好处,注射器很好地鼓励 通过使用 Module 来划分代码。

    虽然受到 Guice 的启发,但它并没有盲目地复制其 API。提供 Pythonic API 胜过忠诚度。

    【讨论】:

      【解决方案3】:

      我没用过,不过Spring Python框架是基于Spring实现的Inversion of Control

      Python 项目中似乎也有一个 Guice:snake-guice

      【讨论】:

        【解决方案4】:

        作为猴子补丁的替代方案,我喜欢 DI。 http://code.google.com/p/snake-guice/ 等新生项目可能符合要求。

        或查看 Dennis Kempin 的博文 Dependency Injection in Python(2008 年 8 月)。

        【讨论】:

          【解决方案5】:

          pinject (https://github.com/google/pinject) 是一种较新的替代方案。它似乎由 Google 维护,并遵循与 Guice (https://code.google.com/p/google-guice/) 类似的模式,它是 Java 对应物。

          【讨论】:

          • 虽然 pinject 看起来很棒,但它多年来一直没有得到维护,拉取请求添加了对 Python 2.6 和 3.x 的支持大约保持开放的时间。
          • 仅供参考,pinject 似乎再次活跃。
          【解决方案6】:

          【讨论】:

            【解决方案7】:

            如果您只想在 Python 中进行依赖注入,则不需要框架。看看Dependency Injection the Python Way。它真的又快又容易,而且只有 c. 50 行代码。

            【讨论】:

            • 我不喜欢这篇文章,因为依赖项并没有真正注入,并且类将依赖于特征定位器。
            【解决方案8】:

            有一个有点奇怪的python-inject 项目。它非常活跃,而且代码比 Spring-python 少很多,但话说回来,我还没有找到使用它的理由。

            【讨论】:

              【解决方案9】:

              将我的 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 GitHub 页面开始获取实际示例 - https://github.com/ets-labs/python-dependency-injector

              【讨论】:

              • 我喜欢这个答案,因为您提供了代码。如果我有机会尝试,我会投票。
              • 嗨@MikeD,谢谢,很高兴听到。这里的代码有点过时了,请转至github.com/ets-labs/python-dependency-injector,以便您找到实际代码。
              【解决方案10】:

              多年使用没有任何 DI 自动装配框架的 Python 和带有 Spring 的 Java,我开始意识到简单的 Python 代码通常不需要依赖注入自动装配的框架(自动装配是 Guice 和 Spring 在 Java 中所做的) ,也就是说,只要做这样的事情就足够了:

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

              这是纯粹的依赖注入(非常简单),但没有自动为您注入它们的神奇框架。

              尽管当我处理更大的应用程序时,这种方法不再适用。所以我想出了injectable 一个微框架,它不会让人感觉非pythonic,但会提供一流的依赖注入自动装配。

              在座右铭 Dependency Injection for Humans™ 下,它看起来是这样的:

              # 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):
                  ...
              

              【讨论】:

                【解决方案11】:

                这是一个依赖注入容器的小例子,它根据构造函数参数名称进行构造函数注入:

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

                【讨论】:

                  【解决方案12】:

                  我做了一个库来做这个 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)
                  

                  【讨论】:

                  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
                  • 我已经放了一些例子,现在更好了吗?
                  • 现在的答案肯定更好。至于内容 - 我不能说:)
                  • 好的,谢谢!所以你只检查答案是否遵循模式而不是内容?
                  • 我通过本网站的特别推荐部分看到了您的回答。无论内容如何,​​都有关于如何写出好的答案的指南 - 您可以在 SO 上找到它们。当您只发布一个链接时 - 它不被认为是一个好的答案。您可以发布链接,但应附上您自己的想法、cmets、代码等。
                  【解决方案13】:

                  Enterprython是一个提供依赖注入的小框架,基于type hints自动构建对象图。

                  【讨论】:

                    【解决方案14】:

                    如果你更喜欢一个非常小的解决方案,那么它就是一个小函数,它只是一个依赖设置器。

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

                    【讨论】:

                    • 这并不比直接实例化对象方便。依赖注入不需要框架。
                    【解决方案15】:

                    有 dyject (http://dyject.com),这是一个适用于 Python 2 和 Python 3 的轻量级框架,它使用内置的 ConfigParser

                    【讨论】:

                      【解决方案16】:

                      如果你想要一个类似(他们说的新的新的)的 guice,我最近在 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

                      【讨论】:

                        【解决方案17】:

                        我最近在 python 中发布了一个简洁的(恕我直言)微库:

                        https://github.com/suned/serum

                        【讨论】:

                          【解决方案18】:

                          我正在积极为 Python >= 3.6 开发 pinject。它很容易使用:

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

                          【讨论】:

                            猜你喜欢
                            • 2014-09-06
                            • 1970-01-01
                            • 2016-08-19
                            • 2015-02-12
                            • 1970-01-01
                            • 1970-01-01
                            • 2010-09-22
                            • 2021-08-13
                            • 1970-01-01
                            相关资源
                            最近更新 更多