問題は、変数cache
が関数一致の範囲内にないことです。これは、2番目の例のように読みたいだけの場合は問題ありませんが、割り当てている場合は、Pythonがローカル変数として解釈します。Python 3を使用している場合は、nonlocal
キーワードを使用してこの問題を解決できます。Python2の場合、残念ながら簡単な回避策はありません。
def f():
v = 0
def x():
return v #works because v is read from the outer scope
def y():
if v == 0: #fails because the variable v is assigned to below
v = 1
#for python3:
def z():
nonlocal v #tell python to search for v in the surrounding scope(s)
if v == 0:
v = 1 #works because you declared the variable as nonlocal
問題はグローバル変数でも同じですglobal
。グローバル変数に割り当てるたびに使用する必要がありますが、読み取るためには使用しないでください。
その背後にある理由の簡単な説明:Pythonインタープリターは、すべての関数を型の特別なオブジェクトにコンパイルしますfunction
。このコンパイル中に、関数が作成するすべてのローカル変数をチェックします(ガベージコレクションなど)。これらの変数名は関数オブジェクト内に保存されます。外部スコープ変数を「シャドウ」する(同じ名前の変数を作成する)ことは完全に合法であるため、global
(またはnonlocal
python3で)明示的に宣言されていない変数はローカル変数と見なされます。
関数が実行されると、インタプリタは検出したすべての変数参照を検索する必要があります。コンパイル中に変数がローカルであることが判明した場合は、関数f_localsディクショナリで検索されます。まだ割り当てられていない場合は、発生した例外が発生します。変数が関数スコープで割り当てられておらず、したがってそのローカルの一部ではない場合、その変数は周囲のスコープで検索されます。変数がそこで見つからない場合、同様の例外が発生します。