Pythonの変数のスコープとは?ローカル変数とグローバル変数の違いを初心者向けに解説
生徒
「先生、Pythonで変数のスコープって何ですか?ローカル変数とかグローバル変数って聞きます」
先生
「スコープは『変数が使える範囲』のことです。ローカル変数は関数の中だけ、グローバル変数はプログラム全体で使える変数ですよ」
生徒
「それぞれどう使い分けるんですか?注意点とかありますか?」
先生
「それは大事な点ですね。まずはローカルとグローバルの違いをわかりやすい例で見ていきましょう!」
1. 変数のスコープとは?
「スコープ」とは、変数が使える範囲のことです。どこで変数を作ったかによって、その変数が「どこから見えるか」「どこで使えるか」が決まります。Pythonでは大きくローカル変数とグローバル変数に分かれ、それぞれに「見える範囲(スコープ)」があります。
大きな町内会で「この町内だけ使える名前」と「町全体で使える名前」があるイメージです。範囲を意識すると、同じ名前の変数があっても混乱しにくくなります。
まずは、ローカルとグローバルの違いがパッとわかる、短い例を見てみましょう。
name = "グローバル" # どこからでも見える(グローバル変数)
def show():
name = "ローカル" # 関数の中だけで使える(ローカル変数)
print("関数の中:", name)
show()
print("関数の外:", name)
解説:関数の中で作ったnameは、その関数の中だけで使える「ローカル変数」です。一方、関数の外で作ったnameは「グローバル変数」で、関数の外からも見えます。同じ名前でも、作った場所が違うと別の変数として扱われるのがスコープのポイントです。
2. ローカル変数とは?
ローカル変数は、関数(または特定の処理のまとまり)の中でだけ使える変数です。関数の外からは見えないので、例えるなら「部屋の中だけで使えるメモ」。同じ名前の変数が外にあっても、関数の中では別のものとして扱われます。
まずは、関数の中では使えるのに、外に出ると使えない例を見てみましょう。
def greet():
message = "こんにちは" # ローカル変数(greetの中だけ)
print(message)
greet()
print(message) # 関数の外なのでエラーになる
実行すると、関数内では「こんにちは」が表示されますが、関数外では使えずエラーになります。
こんにちは
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
NameError: name 'message' is not defined
解説:messageはgreet()の中で作られたため、スコープは「関数の中」に限定されます。そのため、greet()の実行が終わると、外側からはmessageが存在しないものとして扱われます。ローカル変数を使うと、ほかの場所に影響を出しにくく、関数ごとの処理がスッキリ整理できます。
3. グローバル変数とは?
グローバル変数は、関数の外(プログラムの一番上など)で作られ、プログラム全体から参照できる変数です。どの関数からでも同じ値を取り出せるので、例えるなら「町全体で共有している大きな看板」のような存在です。
ただし、便利な反面、どこからでも見えてしまうため、値がいつ・どこで変わったのか追いづらくなることもあります。まずは「関数の中からでも読める」という基本を、シンプルな例で確認しましょう。
greeting = "おはよう" # グローバル変数(プログラム全体で使える)
def say():
print("関数の中:", greeting) # 関数の中からグローバル変数を参照
say()
print("関数の外:", greeting) # 関数の外からも参照できる
実行すると、関数内外どちらでも同じ内容が表示されます。
関数の中: おはよう
関数の外: おはよう
解説:greetingは関数の外で作られているので、say()の中からでもそのまま使えます。このように「いろいろな場所で同じ値を共有したい」ときに便利なのがグローバル変数です。
4. グローバル変数を関数内で変更したいとき
関数内でグローバル変数を変更したい場合は、globalキーワードを使います。これは「この関数はこの変数を外から使ってね」と宣言する感じです。
count = 0
def increment():
global count
count += 1
increment()
increment()
print(count) # 2になります
globalを使わないと、関数内で新しいローカル変数が作られてしまい、混乱する原因になります。
5. スコープと名前解決のルール(LEGBルール)
PythonにはLEGBという「名前を探す順番」の決まりがあります:
- Local(ローカル)— 関数内
- Enclosing(ネストされた関数の外側)
- Global(グローバル)— モジュール全体
- Built‑in(ビルトイン)— Pythonが初めから持っている
この順番で名前を探し、最初に見つかった場所の変数を使います。だから、同じ名前でも場所によって意味が変わることがあります。
6. 実際の例:名前の衝突に注意!
例えば、グローバルにx、そして関数内にもxがあるとどうなるか見てみましょう。
x = "グローバル"
def f():
x = "ローカル"
print(x)
f()
print(x)
出力は「ローカル」「グローバル」です。それぞれ別物として扱われています。
ローカル
グローバル
これがスコープの重要なポイントです。同じ名前でも別々の意味を持てるため、使い分けが必要です。
7. スコープの活用でプログラムをスッキリさせよう
スコープを理解すると、不要なグローバル変数を減らして安全にコードが書けます。ローカル変数を使えば、他の部分に影響を与えずに済むため、バグが減って読みやすくなります。
例えば、設定値や状態をグローバルに保管しすぎると、予想外の動きになることがあります。スコープを分けて考えることで「この変数はここだけ使う」と明確にできます。
8. ネスト(入れ子)とスコープ
関数の中にさらに関数を作ると、外側の関数の変数を使うケースがあります。このときもスコープが重要です。
def outer():
msg = "外のメッセージ"
def inner():
print(msg) # enclosingスコープのmsgを使う
inner()
outer()
この例では、inner関数がouterのmsgを使えます。これは「ネストされた関数の外側」がスコープに含まれているため可能です。
まとめ
Pythonの変数のスコープについて学んできましたが、振り返ってみると、スコープはプログラムを書くうえで欠かせない基礎の一つであり、ローカル変数とグローバル変数の役割を理解しておかないと大きな混乱を招くことがよく分かります。特に、プログラムの安全性や可読性を保つためには「どの変数がどの範囲で生きているのか」を意識することがとても重要であり、正しく使い分けることで予期しないバグを防げます。ローカル変数は関数の中だけで使える限定的な変数であり、外部の処理に影響を及ぼさないため、安心して関数ごとの処理をまとめられます。反対にグローバル変数はプログラムのどこからでも参照できる便利な存在ですが、安易に使いすぎると意図せぬ変更が行われたり、後からコードを読んだ人が理解しづらくなったりします。 また、Pythonには変数を探す順番であるLEGBルールがあり、この仕組みを理解していると、同じ名前の変数が複数あるときにどれが使われるのかが瞬時に判断できるようになります。複雑なプログラムになればなるほど、名前の衝突やスコープの重なりに注意が必要なので、この考え方は非常に役立ちます。特に関数の中に関数を作るネスト構造では、外側の関数の変数が内側から使えるという特徴があり、これが便利な一方で誤解を招く原因にもなり得るため、スコープを常に意識してコードを書くことが求められます。 スコープを理解することは、コードの見通しを良くし、処理を整理し、予期せぬ動作を防ぐために非常に大切です。たとえば設定値をグローバルに置きすぎるとどこで変更されたのか分からなくなり、管理が難しくなります。逆にローカル変数を適切に使えば、機能ごとに独立した処理構造を作ることができ、プログラム全体の品質向上につながります。さらに、グローバル変数の値を関数内で変更する場合にはglobalキーワードが必要であるという仕組みも、Pythonならではのルールであり、この理解が不十分だと混乱が起きやすい部分です。 実際の開発では、関数の役割を明確にし、外部から影響を受けないようローカル変数を中心に設計することがよくあります。スコープの活用は、長期的な保守性にもつながるため、初心者の段階でしっかり理解しておくのが理想的です。また、関数の外側の変数を利用するケースでは、ネストされた関数をどう扱うかも考える必要があります。外側の値をそのまま利用するのか、別の変数として扱うのかによって結果が変わるため、スコープの理解は欠かせません。 以上を踏まえると、Pythonのスコープは単なる仕組みではなく、プログラム全体を整理し、動作を安定させるための大切な設計の基盤であるといえます。ローカル変数とグローバル変数、LEGBルール、ネスト構造とスコープの関係など、どれもプログラムを正しく理解し書いていくうえで不可欠な内容です。これらを身につけることで、より複雑な処理にも対応できる柔軟な思考が育ち、トラブル時の原因特定もスムーズに行えるようになります。
スコープを意識したサンプルコード
最後に、ローカル変数・グローバル変数・ネストした関数のスコープをすべて使った総合例です。
count = 0 # グローバル変数
def outer():
message = "外側のメッセージ" # ローカル変数(outerのスコープ)
def inner():
global count
count += 1
print(message, "番号:", count)
inner()
outer()
outer()
print("最終カウント:", count)
この例では、外側の関数outerで作られたローカル変数messageをinner関数が参照しています。また、inner関数の中でglobalを宣言することで外のcount変数を変更できるようになっています。ローカル・グローバル・ネスト、すべてのスコープがどのように扱われるかを理解するのに役立つ構造になっています。
生徒
「今日のスコープの話、最初は難しいと思ったけど、例を見たら仕組みが分かりやすくなりました!」
先生
「とても大事な考え方だから、ゆっくり理解していけば大丈夫ですよ。ローカルとグローバルの違いがしっかり分かると、コードがグッと整理されます。」
生徒
「グローバルを増やしすぎると危ないっていうのも意外でした。便利だからたくさん使ったほうがいいと思っていました…!」
先生
「便利なんですが、どこからでも変更されると管理が大変になりますからね。ローカルが基本、必要なときだけグローバル、という意識が大切ですね。」
生徒
「ネストした関数のスコープも面白かったです。外側の変数を内側で使えるなんて知りませんでした!」
先生
「Pythonの特徴の一つですね。これを理解しておくと、関数型の書き方や応用的なコードにも応用できますよ。」
生徒
「次は自分のプログラムでもスコープを意識して書いてみます!」
先生
「いいですね。スコープの理解は必ず力になりますよ。一緒にまた練習していきましょう。」