Flask アプリケーションでグローバル変数を不用意に使うと、リクエスト間でデータが混在したり、マルチスレッド環境で予期しない動作を引き起こす。
典型的なアンチパターン
from flask import Flask app = Flask(__name__) # 危険: グローバル変数でリクエストごとのデータを保持 current_user = None request_count = 0 @app.route('/login') def login(): global current_user current_user = 'Alice' # 全リクエストで共有されてしまう return 'Logged in' @app.route('/profile') def profile(): return f'User: {current_user}' # 別ユーザーのデータが見える可能性
この実装では、ユーザー A がログインした後、ユーザー B が /profile にアクセスすると、ユーザー A の情報が表示されてしまう。
なぜ問題なのか
Flask は Gunicorn などの WSGI サーバー上で複数のワーカープロセスやスレッドで動作する。グローバル変数は以下の問題を引き起こす。
| スレッド間共有 | 複数リクエストが同時に同じ変数を読み書きする |
| レースコンディション | 変数の更新が競合してデータが破損する |
| リクエスト漏洩 | あるユーザーのデータが別ユーザーに見える |
正しいアプローチ
リクエストごとのデータは g オブジェクトを使う。
from flask import Flask, g app = Flask(__name__) @app.route('/login') def login(): g.current_user = 'Alice' # リクエストコンテキストに紐づく return 'Logged in'
セッションで永続化する場合は session を使う。
from flask import session @app.route('/login') def login(): session['user'] = 'Alice' return 'Logged in'
アプリケーション全体の設定
アプリケーション全体で共有する設定は app.config を使う。
app.config['MAX_UPLOAD_SIZE'] = 1024 * 1024
本当にグローバルが必要な場合
キャッシュやコネクションプールなど、本当に共有が必要な場合はスレッドセーフなデータ構造を使う。
from threading import Lock cache = {} cache_lock = Lock() def get_cached(key): with cache_lock: return cache.get(key)
ただし、通常は Flask-Caching や Redis などの専用ツールを使うべきである。