Python DI Framework Pinject
Googleの人が作った (Google公式のProjectではない)Python DI Frameworkらしい.
結構簡単に使える.
数人で開発する場合に,全体のロジックやSWアーキは自分で握って,
クラス単位で他人が作成したものに差し替えたいという場合は,
スクリプトといえど,DIが使いたくなる.
(モジュール/クラスを思っても見ない感じにいじられるとたまったものではない)
Installation
sudo pip install pinject
Condensed Summary
dependency injection
- implicit
import pinject class OuterClass(object): def __init__(self, inner_class): self.inner_class = inner_class pass class InnerClass(object): def __init__(self): self.forty_two = 42 pass obj_graph = pinject.new_object_graph() outer_class = obj_graph.provide(OuterClass) print outer_class.inner_class.forty_two
auto init
import pinject class ClassWithTediousInitializer(object): @pinject.copy_args_to_internal_fields def __init__(self, foo, bar, baz, quux): pass cwti = ClassWithTediousInitializer('a-bar', 'a-foo', 'a-baz', 'a-quux') print cwti._foo
Binding specs
import pinject class SomeClass(object): def __init__(self, long_name, long_name2, outer_class): self.long_name = long_name self.long_name2 = long_name2 self.outer_class = outer_class pass pass class SomeReallyLongClassName(object): def __init__(self): self.foo = 'foo' pass pass class SomeReallyLongClassName2(object): def __init__(self): self.hoge = 'hoge' pass pass class InnerClass(object): """ """ def __init__(self, ): """ """ self.name = "inner_class" pass pass class OuterClass(object): """ """ def __init__(self, inner_class): """ """ self.inner_class = inner_class pass pass class MyBindingSpec(pinject.BindingSpec): def configure(self, bind): bind('long_name', to_class=SomeReallyLongClassName) bind('long_name2', to_class=SomeReallyLongClassName2, ) bind('outer_class', to_class=OuterClass) #bind('inner_class', to_class=InnerClass) pass pass obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()]) some_class = obj_graph.provide(SomeClass) print some_class.long_name.foo print some_class.long_name2.hoge print some_class.outer_class.inner_class.name
- binding specs dependency
import pinject class ClassOne(object): def __init__(self, foo): self.foo = foo pass pass class BindingSpecOne(pinject.BindingSpec): def configure(self, bind): bind('foo', to_instance='foo-') pass pass class ClassTwo(object): def __init__(self, class_one, bar): self.foobar = class_one.foo + bar pass pass class BindingSpecTwo(pinject.BindingSpec): def configure(self, bind): bind('bar', to_instance='-bar') pass def dependencies(self): return [BindingSpecOne()] pass obj_graph = pinject.new_object_graph(binding_specs=[BindingSpecTwo()]) class_two = obj_graph.provide(ClassTwo) print class_two.foobar
scope
- prototype (defaultはsingleton)
import pinject class SomeClass(object): def __init__(self, foo): self.foo = foo pass pass class SomeBindingSpec(pinject.BindingSpec): @pinject.provides(in_scope=pinject.PROTOTYPE) def provide_foo(self): return object() pass obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()]) some_class_1 = obj_graph.provide(SomeClass) some_class_2 = obj_graph.provide(SomeClass) print some_class_1.foo is some_class_2.foo
provider bindings
- scopeがprotyotypeになるような別のやり方
- 次のprovide_fooをfooにしてもTrueになるが,provide_fooではinstanceを常に作る
import pinject class Foo(object): def __init__(self): self.forty_two = 42 pass pass class SomeBindingSpec(pinject.BindingSpec): def configure(self, bind): bind('foo', to_class=Foo, in_scope=pinject.PROTOTYPE) pass pass class NeedsProvider(object): def __init__(self, provide_foo): self.provide_foo = provide_foo pass pass obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()]) needs_provider = obj_graph.provide(NeedsProvider) print needs_provider.provide_foo() is needs_provider.provide_foo()