下記の関数定義中の変数bar
は、関数のブロック内にbar
の定義がないためグローバル変数と解釈されます。
def foo():
print(bar)
下記のコードは、foo
の呼び出し前にグローバル変数bar
が定義されているので成功します。
bar = 4
def foo():
print(bar)
foo() # => 4
foo
のグローバル変数は、foo
のコードオブジェクトの属性co_names
で確認できます。
foo.__code__.co_names # => ('print', 'bar')
ちなみにPythonの公式ドキュメントでは、co_names
はローカル変数名のtuple
と書いてありますが、(ローカル変数名と自由変数を除く)名前の間違いです。
下記の関数定義中のbar
は、関数のブロック内にbar
が定義されているため、ローカル変数と解釈されます。
def foo():
print(bar)
bar = 3
foo.__code__.co_names # => ('print',)
foo
のローカル変数は、foo
のコードオブジェクトの属性co_varnames
で確認できます。
foo.__code__.co_varnames # => ('bar',)
この解釈は、関数定義が行われたときに決まるため、bar
の定義の前にbar
があってもグローバル変数とは解釈されず、次のようにエラーになります。
bar = 4
def foo():
print(bar)
bar = 3
foo()
# => UnboundLocalError: local variable 'bar' referenced before assignment
つまり、関数ブロック中の名前は、関数定義の段階でグローバル変数かローカル変数か(もしくは自由変数か)に決まっており、名前への代入時点でグローバル変数からローカル変数にリバインドされるのではありません。
さらに、リストなどの内包表記は新たなスコープを導入しますが、最初のfor
に対応するイテラブルのみ、外側のスコープで解釈されます。下記の例は成功しますが、リスト内包表記内の3つのbar
のうち、一番右のbar
はfoo
のスコープ、すなわちグローバル変数のbar
と解釈されるためです。
bar = range(3)
def foo():
print([bar for bar in bar])
foo() # => [0, 1, 2]