python依赖注入框架
Inject的Python项目详细描述
python注入
依赖注入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=False
到inject.configure
、inject.configure_once
或inject.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
出资人
- 伊凡·科罗布科夫@ivankorobkov
- 杰米·怀恩@jaimewyant
- 塞巴斯蒂安·布钦斯基@Enforcer
- 奥列克桑德费多罗夫@Fedorof
- cselvaraj@cselvaraj
- 陆雨晴@SixExtreme
- 安德鲁·威廉·博巴@andrewborba10
- jdmeyer3@jdmeyer3
- 亚历克斯·格罗弗@ajgrover