LEGBルールは、Pythonにおける名前空間(スコープ)の検索ルールです。この略語は以下のように解釈されます:
len, list, など)。Pythonが変数を見つけると、まずローカルで探し、次に内包された関数で探し、その後モジュールのグローバル領域で探し、最後にビルトインオブジェクトの名前空間で探します:
def outer(): x = 'enclosing' def inner(): x = 'local' print(x) inner() outer() # 'local'
inner()内でxへの代入を削除すると、Pythonはouterの内包スコープからxを取得します。もしそこにも変数がなければ、グローバルで、次にビルトインから探します。
変数の外部スコープを変更する際に
nonlocalまたはglobalを宣言し忘れた場合、関数の動作はどう変わりますか?
回答:
外部スコープの変数を内包関数内で nonlocal(またはモジュール内にある場合は global)を宣言せずに変更しようとすると、Pythonは新しいローカル変数を作成し、外部変数は変更されません。
例:
x = 10 def foo(): x = 20 # これは新しいローカルxで、グローバルには影響しない foo() print(x) # 10
グローバルxを変更するためには:
def foo(): global x x = 20
外部関数の変数については、nonlocalを使用してください。
ストーリー1
教育プロジェクトで呼び出し回数をカウントするために内包関数を使用しました。開発者は次のように書きました:
def counter(): count = 0 def inc(): count += 1 return count return inc
しかし、inc()内でcountが新しいもの(ローカルcountが作成される)と見なされたため、UnboundLocalErrorが発生しました。解決策:countをnonlocalとして宣言すること。
ストーリー2
Webアプリケーションで、ハンドラー内でグローバルに設定されたキャッシュを変更したいと考えました:
cache = {} def add_to_cache(key, value): cache[key] = value
しかし、もし関数内で完全にキャッシュを書き換えようとした場合(例えば cache = {key: value} のように)、新しいローカルcacheが作成され、グローバルなものとは無関係になりました。これはglobal cacheが不足していたためです。
ストーリー3
大規模なETLシステムでバグが発生しました。プログラマは関数内でresult変数を明示的に初期化せず、外部スコープから取られると期待していました。しかし、数回の反復の後、結果が狂い始めました。なぜなら、内部でresult += valueが実行され、result = result + value(nonlocal/globalなし)になるからです。これは各呼び出しでresultが再初期化されてしまったからです。