Flask の view で依存を排除したい
Flask を使ってアプリケーションを書いていてどうやってやるんだろうと思ったので、ちょっと試してみた。
Flask の view 関数内でロジックとなる部分を呼び出す場合 view 関数でインスタンスを生成する。
#!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask # ロジック部分のクラス class Foo(object): def users(self): return 'Foo.users' # ロジック部分のクラス class Bar(object): def users(self): return 'Bar.users' @app.route('/') def index(): foo = Foo() users = foo.users() return dict(foo=users) if __name__ == '__main__': app.debug = True app.run()
こんな感じ。
ある程度の規模や保守/運用の時に改修が入った際に Foo() を Bar() に差し替えたいというのがあったら直接書き換えないといけない。
要は外部から注入して views のなかはいじらなくて済むようにしたい。
# テストで差し替えたい場合は mock を使えばいいと思う
Pyramid はここら辺を Resource Factory という仕組みを使えばうまい事できるそう。
http://d.hatena.ne.jp/imagawa_yakata/20120117/1326601571
Flask でもおんなじような事をしたい。
Flask 0.9 から app_context というのが入った。
#!/usr/bin/env python # -*- coding: utf-8 -*- from functools import wraps from flask import Flask, current_app app = Flask(__name__) class Foo(object): def users(self): return 'Foo.users' class Bar(object): def users(self): return 'Bar.users' with app.app_context(): current_app.injections = {} def inject(**injections): def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): for k, v in injections.iteritems(): current_app.containers[k] = v return f(*args, **kwargs) return decorated_function return decorator @app.route('/') @inject(foo=Foo, bar=Bar) def foo(): service = current_app.injections['foo'] foo = service() service = current_app.injections['bar'] bar = service() return dict(foo=foo.users(), bar=bar.users) if __name__ == '__main__': app.debug = True app.run()
こんな感じ?
current_app をコンテナとして利用したらできた。
これが正しいやりかたかどうか自信ないので、こうした方が良いとかアドバイス欲しいです。