コンテキストローカル—Werkzeugドキュメント

提供:Dev Guides
Werkzeug/docs/2.0.x/local
移動先:案内検索

コンテキストローカル

遅かれ早かれ、すべてのビューやヘルパー関数などに必要なものがいくつかあります。 PHPでは、進むべき道はグローバル変数です。 ただし、WSGIアプリケーションでは、大きな欠点がない限り、これは不可能です。グローバル名前空間を操作するとすぐに、アプリケーションはスレッドセーフではなくなります。

Python標準ライブラリには、「スレッドローカル」(またはスレッドローカルデータ)と呼ばれる概念があります。 スレッドローカルは、スレッドセーフでスレッド固有の方法でデータを入れて後で戻すことができるグローバルオブジェクトです。 つまり、スレッドローカルオブジェクトに値を設定または取得するたびに、スレッドローカルオブジェクトは現在のスレッドをチェックし、スレッドに対応する値(存在する場合)を取得します。 したがって、誤って別のスレッドのデータを取得することはありません。

ただし、このアプローチにはいくつかの欠点があります。 たとえば、Pythonには、スレッド以外にも他の種類の同時実行性があります。 非常に人気のあるものはグリーンレットです。 また、すべてのリクエストが独自のスレッドを取得するかどうかは、WSGIでは保証されません。 リクエストが前のリクエストのスレッドを再利用しているため、スレッドローカルオブジェクトにデータが残っている可能性があります。

Werkzeugは、 werkzeug.local と呼ばれる独自のローカルデータストレージの実装を提供します。 このアプローチは、スレッドローカルと同様の機能を提供しますが、グリーンレットでも機能します。

これは、werkzeug.localを使用する方法の簡単な例です。

from werkzeug.local import Local, LocalManager

local = Local()
local_manager = LocalManager([local])

def application(environ, start_response):
    local.request = request = Request(environ)
    ...

application = local_manager.make_middleware(application)

これにより、リクエストが local.request にバインドされます。 同じコンテキストでこの割り当ての後に実行される他のすべてのコードは、local.requestに安全にアクセスでき、同じリクエストオブジェクトを取得します。 ローカルマネージャの make_middleware メソッドは、リクエスト後にローカルオブジェクトへのすべての参照がクリアされることを保証します。

同じコンテキストは、同じスレッドと同じプロセスで同じグリーンレット(グリーンレットを使用している場合)を意味します。

リクエストオブジェクトがローカルオブジェクトにまだ設定されておらず、それにアクセスしようとすると、 AttributeError が発生します。 getattr を使用して、次のことを回避できます。

def get_request():
    return getattr(local, 'request', None)

これは、リクエストを取得しようとするか、リクエストが(まだ?)利用できない場合は None を返します。

ローカルオブジェクトはそれ自体を管理できないことに注意してください。そのため、ローカルマネージャーが必要です。 ローカルマネージャーに複数のローカルを渡すか、後で manager.locals に追加して追加することができます。マネージャーがクリーンアップするたびに、このコンテキストのローカルに残っているすべてのデータがクリーンアップされます。