Google 製の DI フレームワークの Pinject を試してみた
Google が作っている DI フレームワークに Pinject というのがあるのを知った。
Injector とどう違うのか試してみた。
詳しくは GitHub の Pinject のドキュメント参照。
# -*- coding: utf-8 -*- import pinject class Base(object): def save(self, path): raise NotImplemented() class FileStorage(Base): def save(self, path): return 'file save' class RiakCSStorage(Base): def save(self, path): return 'riak save' class Storage(object): def __init__(self, Storage): self.storage = Storage() def save(self, path): return self.storage.save(path) class BindingSpec(pinject.BindingSpec): def configure(self, bind): bind('Storage', to_class=FileStorage) if __name__ == '__main__': inject = pinject.new_object_graph(binding_specs=[BindingSpec()]) service = inject.provide(Storage) print(service.save('foo'))
基本形。アノテーションとか無くて、暗黙の了解で注入する。
BindingSpec クラス内の bind() で注入先の変数名を指定してる。
実行すると
file save
と表示される。
FileStorage じゃなくて to_class=RiakCSStorage にすると、
riak save
と表示される。
暗黙は嫌だ*1、BindingSpec クラス、注入先の Storage クラスを読んだら明示的に何が注入されるのか見たい場合は、デコレータを使って明示する。
# -*- coding: utf-8 -*- import pinject class Base(object): def save(self, path): raise NotImplemented() class FileStorage(Base): def save(self, path): return 'file save' class RiakCSStorage(Base): def save(self, path): return 'riak save' class Storage(object): @pinject.annotate_arg('Storage', 'Storage-Anno') def __init__(self, Storage): self.storage = Storage() def save(self, path): return self.storage.save(path) class BindingSpec(pinject.BindingSpec): @pinject.provides('Storage', annotated_with='Storage-Anno') def provide_storage(self): return RiakCSStorage # RiakCSStorage() とすればインスタンスが渡る if __name__ == '__main__': inject = pinject.new_object_graph(binding_specs=[BindingSpec()]) service = inject.provide(Storage) print(service.save('foo'))
BindingSpec クラスでプロバイダーを指定してやる。
Injector にせよ Pinject にせよ元々は Google の Guice が元ネタだからとても似ている。
作成したコードは Injector を使ったのよりシンプルに見える。
良いなと思ったのが Bind 先の変数名に文字列が使える事。
Injector は Key() で指定したオブジェクト名だったり、bind 時に設定したオブジェクトだったりするのでシンプル。
ただし Flask と連携する前提だと Flask-Injector が既にある分そっちの方が楽。
Pinject の方だと他にも Partial injection とかできるようだけど未調査。
因に Injector の作者による Pinject との違いについて。
Pinject: A dependency injection library for python. : Python
*1:Explicit is better than implicit