python依赖注入框架

Inject的Python项目详细描述


python注入Build Status

依赖注入python的方式,好方法。不是圭斯港或春天。

主要功能

  • 快。
  • 线程安全。
  • 使用简单。
  • 不窃取类构造函数。
  • 不尝试管理应用程序对象图。
  • 透明地集成到测试中。
  • 支持Python2.7和Python3.3+。
  • 在Python3.5+中支持类型提示。
  • 利用类型注释的自动参数。

安装

使用pip安装最新版本:

pip install inject

自动参数示例

@inject.autoparams返回一个decorator,该decorator自动将参数注入函数 使用类型批注的。这仅在python>;=3.5中受支持。

@inject.autoparams()defrefresh_cache(cache:RedisCache,db:DbInterface):pass

有一个选项指定要插入哪些参数而不尝试 注入一切:

@inject.autoparams('cache','db')defsign_up(name,email,cache,db):pass

逐步示例

# Import the inject module.importinject# `inject.instance` requests dependencies from the injector.deffoo(bar):cache=inject.instance(Cache)cache.save('bar',bar)# `inject.params` injects dependencies as keyword arguments or positional argument. # Also you can use @inject.autoparams in Python 3.5, see the example above.@inject.params(cache=Cache,user=CurrentUser)defbaz(foo,cache=None,user=None):cache.save('foo',foo,user)# this can be called in different ways:# with injected argumentsbaz('foo')# with positional argumentsbaz('foo',my_cache)# with keyword argumentsbaz('foo',my_cache,user=current_user)# `inject.param` is deprecated, use `inject.params` instead.@inject.param('cache',Cache)defbar(foo,cache=None):cache.save('foo',foo)# `inject.attr` creates properties (descriptors) which request dependencies on access.classUser(object):cache=inject.attr(Cache)def__init__(self,id):self.id=iddefsave(self):self.cache.save('users',self)@classmethoddefload(cls,id):returncls.cache.load('users',id)# Create an optional configuration.defmy_config(binder):binder.install(my_config2)# Add bindings from another config.binder.bind(Cache,RedisCache('localhost:1234'))# Configure a shared injector.inject.configure(my_config)# Instantiate User as a normal class. Its `cache` dependency is injected when accessed.user=User(10)user.save()# Call the functions, the dependencies are automatically injected.foo('Hello')bar('world')

与django一起使用

django可以多次加载某些模块,这可能导致 InjectorException: Injector is already configured。您可以使用configure_once 当喷油器不存在时,保证只运行一次:

importinjectinject.configure_once(my_config)

测试

在测试中,使用inject.clear_and_configure(callable)在设置时创建新的注入器, 也可以选择inject.clear()在拆卸时清理:

classMyTest(unittest.TestCase):defsetUp(self):inject.clear_and_configure(lambdabinder:binder.bind(Cache,Mock() \
            .bind(Validator,TestValidator())deftearDown(self):inject.clear()

螺纹安全性

配置之后,注入器是线程安全的,可以被多个线程安全地重用。

绑定类型

instance绑定总是返回相同的实例:

redis=RedisCache(address='localhost:1234')defconfig(binder):binder.bind(Cache,redis)

constructor绑定在注入时创建单例:

defconfig(binder):# Creates a redis cache singleton on first injection.binder.bind_to_constructor(Cache,lambda:RedisCache(address='localhost:1234'))

provider绑定在注入时调用提供程序:

defget_my_thread_local_cache():passdefconfig(binder):# Executes the provider on each injection.binder.bind_to_provider(Cache,get_my_thread_local_cache)

runtime绑定在注入时自动创建单例,无需配置。 例如,只有Config类绑定存在,其他绑定是运行时的:

classConfig(object):passclassCache(object):config=inject.attr(Config)classDb(object):config=inject.attr(Config)classUser(object):cache=inject.attr(Cache)db=inject.attr(Db)@classmethoddefload(cls,user_id):returncls.cache.load('users',user_id)orcls.db.load('users',user_id)inject.configure(lambdabinder:binder.bind(Config,load_config_file()))user=User.load(10)

禁用运行时绑定

有时运行时绑定会导致意外行为。如果你忘了说 要将实例绑定到类,inject将尝试隐式实例化它。

如果无意中创建了带有默认参数的实例,则可能导致 很难调试错误。要禁用运行时绑定并确保仅 显式绑定实例被注入,传递bind_in_runtime=Falseinject.configureinject.configure_onceinject.clear_and_configure

在这种情况下,inject当代码 尝试获取未绑定的实例。

按键

可以使用任何哈希对象作为绑定键。例如:

importinjectinject.configure(lambdabinder: \
    binder.bind('host','localhost') \
    binder.bind('port',1234))

为什么没有望远镜?

我已经在java中使用guice和spring很多年了,我不喜欢它们的作用域。 python-inject默认情况下,将对象创建为singleton。它不需要原型范围 因为python-inject不会窃取您的类 施工人员。按照您喜欢的方式创建实例,然后将依赖项注入到其中。

其他作用域(如请求作用域或会话作用域)是脆弱的,会引入高度耦合, 而且很难测试。在python-inject中编写可以是线程本地的自定义提供程序, 请求本地等

例如,线程本地当前用户提供程序:

importinjectimportthreading# Given a user class.classUser(object):pass# Create a thread-local current user storage._LOCAL=threading.local()defget_current_user():returngetattr(_LOCAL,'user',None)defset_current_user(user):_LOCAL.user=user# Bind User to a custom provider.inject.configure(lambdabinder:binder.bind_to_provider(User,get_current_user))# Inject the current user.@inject.params(user=User)deffoo(user):pass

链接

许可证

apache许可证2.0

出资人

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
JPanel的java滚动窗格?   java JPA查询方法:findTopX,其中X是给定的(变量)数?   当应用程序在Oreo中处于后台时,java音乐服务在几秒钟后不工作   java通过TCP流发送密钥编码的字符串BadPaddingException with Windows   java在这里构建代码的更好方法是什么?   如何使用Java(无给定参数)检查列表中是否有数字   跨多个JVM的java事务控制   dataframe如何使用SparkJavaAPI的MapFunction和ReduceFunction在集群上并行处理这个问题?   java如何在多模块spring引导中配置yml文件   已安装java JDBC驱动程序,但出现异常   JUnit 4中的java,有没有一种方法可以在扩展BlockJUnit4ClassRunner的自定义运行程序中,在all@BeforeClass之前运行一段代码   继续未能选择JAVA上的radioButton   java如何通过PHP代码运行shell命令?   java JSlider SynthLookandFeel填充颜色   java给定一个数字,打印下三个数字   java SpringMVC(安全)403错误   java Graphhopper从装载的obb文件系统加载路由信息时出错   java安全工具扫描问题,发现依赖默认编码:新字符串(字节[])   java如何获取嵌套字段