Pythonには名前空間というものがあります。それぞれの及ぶ範囲があるというイメージです。
例えば、ある関数の中で定義された変数は、別の関数で定義された同じ名前の変数でもそれぞれは別物で、それぞれの関数の中で参照されるということです。
また、だからといって、互いに全く参照できないという訳ではなく、その範囲であるスコープを操作して参照する方法もあります。
具体的見ていく方が理解しやすいのでさっそくやっていきましょう。
グローバル名前空間とグローバル変数
いきなり変数を宣言して、関数でその変数を利用したりするコードを書きます。プログラミングでメインのコードを書くときは、ほぼこういうパターンでしょうけども、これはグローバル名前空間として定義され、そこで定義された変数はグローバル変数と言います。
次のようなコードを用意してみます。(変数のネタを交響詩編エウレカセブンにしてみました。)
lfo = "ニルヴァーシュ"
print(lfo)
lfo = "ニルヴァーシュ"
def lfo_name():
print(lfo)
lfo_name()
変数を定義して、それをそのままコードのトップレベルの位置でprint()で出力しているものと、関数を定義してその中から変数を参照し、関数を呼び出しているコードです。
ここではあえてコードの実行はしませんが、変数の値がどちらもprint()で出力されます。
ここで定義した変数lfoはグローバル変数となります。このグローバル変数は、関数の中から扱うことができるということはわかると思います。
それでは、関数定義をしたコードの方を、以下のように書き換えてみます。
lfo = "ニルヴァーシュ"
def lfo_name():
print(lfo)
lfo = "type ZERO"
print("LFO TYPE", lfo)
lfo_name()
変数をprint()で出力した後に、新たに変数の値を書き換えて再度出力するというコードになっています。
これを実行すると次のようにエラーになってしまいます。
値を書き換えた変数は、関数内のローカル変数として定義することになっていて、実行時にこの変数を指定する前に、参照されているというエラーになっています。
次のように書き換えるとエラーにはなりません。(ふぁいるめscope.py)
lfo = "ニルヴァーシュ"
def lfo_name():
lfo = "type ZERO"
print("LFO TYPE", lfo)
print(lfo)
lfo_name()
実行してみます。(ファイル名をscope.pyにしてAtomで実行しています)
変数名は同じですが、関数の外はグローバル変数、関数の中はローカル変数としてそれぞれ出力されているのがわかります。関数内で宣言した変数は、関数内をスコープの範囲として参照されるので、エラーのような書き方をすれば宣言されていない変数があるとされて実行できないというわけです。
globalで値を書き換える
では、最初に定義したグローバル変数を、ローカルの関数内から書き換える方法をやってみましょう。
それには、globalキーワードを使います。
関数内にglobalと置いた後に変数を置きます。
コードを次のように書いてみましょう。
lfo = "ニルヴァーシュ"
def lfo_name():
global lfo
lfo = "type ZERO"
print("ローカル:", lfo)
print("グローバル:", lfo)
lfo_name()
print("グローバル:", lfo)
最初に宣言されたグローバル変数を、関数内でglobalキーワードと共に置いています。区別するためにprint()はそれぞれの位置をしめす文字列を最初に出力するようにしています。
コードを実行してみましょう。
グローバル変数の値が書き換えられているのがわかるでしょうか。
最初のprint()では、コードを上から実行していく訳ですから、最初に定義した変数の値を出力しています。そして関数を呼び出すと、関数内で与えられた値を出力しています。最後のprintでは、関数内のglobalで値が書き換えられた為に、同じコードでも最初とは違った値がグローバル変数で出力されているのがわかります。
locals()とglobals()
Pythonには名前空間の内容にアクセスするための関数があり、これを使うと値を辞書型で返してくれます。locals()とglobals()の2つです。
locals()は、ローカル名前空間の内容を辞書型で示してくれます。
globals()は、グローバル名前空間の内容を辞書型で示してくれます。
上で使ったコードを利用して確認してみましょう。
lfo = "ニルヴァーシュ"
def lfo_name():
lfo = "type ZERO"
print("ローカル:", locals())
lfo_name()
関数内の変数をローカル変数のみにして、print()関数でlocals()を出力しています。
実行するとこうなります。
(コードの不要な部分をコメントアウトしています)
実行結果を見ると、辞書型で変数名と変数の値が出力されています。ローカル名前空間での値であることがわかります。
これを次のようにglobalキーワードを使って書き換えたものはどうなるでしょうか。
lfo = "ニルヴァーシュ"
def lfo_name():
global lfo
lfo = "type ZERO"
print("ローカル:", locals())
lfo_name()
違いはわかりますよね。globalキーワードを使って変数を関数内に置いています。
実行してみましょう。
結果を見ると、値がありません。globalを使っているので、ローカル名前空間の値を使っていないということがわかります。(裏を返せば、グローバル名前空間の値を使っているということになります)
では、今度はglobals()を使ってみましょう。
次のようにコードを変えてみます。
lfo = "ニルヴァーシュ"
def lfo_name():
global lfo
lfo = "type ZERO"
print("ローカル:", lfo)
print("グローバル:", globals())
lfo_name()
print("グローバル:", globals())
グローバル空間でのprint()関数に、globals()を使って内容を見てみましょう。
実行するとこうなります。
ちょっと見づらいですが、これはグローバル空間で宣言されているものを全て表示しているためです。関数にドキュメントなどがあればそのドキュメントを、また関数名なども表示してくれる訳ですが、ここでは細かく見るのはやめておきましょう。
‘__name__’ : ‘__main__’ というものが最初に見えますが、これがあると、Pythonはこのコードを一番初めに実行しているものということになります。メインで実行しているのプログラムはここであるという特別な意味を表す名前です。また別の機会に触れるのでこういうものがあるということだけ頭にいれておきましょう。
このアンダースコア2つで挟まれたこの書き方は、Python自体が使う変数として予約されたものなので、基本的に自分の変数として使ったりして変更したりしないようにしましょう。
さて、ここで表示されている中で、赤線で印をつけている部分があります。グローバル名前空間で使っている変数と値をこうして確認することができたわけです。
まとめ
Pythonの名前空間を見てきました。グローバル名前空間とローカル名前空間があります。別の空間で定義した変数は同じ名前でも別のものを参照することになります。
関数内で定義した変数はローカル変数として、そのローカルの範囲(スコープ)で参照されます。グローバル変数は、関数内からも参照できます。
関数内でグローバル変数を取得して、その値を書き換えることはできません。そういった操作をするには、globalキーワードに続けて変数を置くと可能になります。
locals()、globals()を使うと、ローカル名前空間、グローバル名前空間のそれぞれの内容を辞書型で確認することができます。