LoginSignup
3
2

More than 3 years have passed since last update.

関数中でグローバル変数と同名のローカル変数を定義した場合

Last updated at Posted at 2020-02-23

下記の関数定義中の変数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のうち、一番右のbarfooのスコープ、すなわちグローバル変数のbarと解釈されるためです。

bar = range(3)

def foo():
    print([bar for bar in bar])

foo()  # => [0, 1, 2]
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2