MENU

Pythonのスコープとは?変数が使える範囲をわかりやすく解説

※写真はイメージです。実物とは異なる場合があります。

  • URLをコピーしました!

Pythonを勉強していると、ある場所では使えるのに別の場所では「そんな変数はありません」とエラーが出てしまう、という経験をしたことがあるかもしれません。

これはPythonの「スコープ(scope)」という仕組みが関係しています。スコープとは簡単に言うと「変数が有効な範囲」のことです。

プログラムの中で作った変数が、どこまで届くのか。このルールを正しく理解していないと、意図しない動作やエラーに悩まされることになります。今回は、初心者の方が特につまずきやすい「ローカル変数」と「グローバル変数」の違いを中心に、Pythonのスコープについて詳しく解説します。

目次

スコープの基本概念と「名前空間」

スコープを理解するために、まず知っておきたいのが「名前空間(namespace)」という考え方です。

名前空間とは、名前(変数名)からオブジェクト(中身の値など)への対応付けのことです。Pythonでは、変数を定義した場所によって、その変数が所属する「名前空間」が決まります。

例えば、家の中に「リビング」と「個室」があると考えてみてください。リビングにあるリモコンは家族全員が使えますが、個室の中に隠して置いた日記帳は、その部屋にいる人にしか見えません。これと同じように、Pythonでも「どこで定義したか」によって、その変数が参照できる範囲(スコープ)が変わるのです。

ローカル変数:関数の中だけの専用変数

関数の中で定義された変数を「ローカル変数」と呼びます。

ローカル変数の最大の特徴は、「その関数の中だけでしか使えない」ということです。関数というひとまとまりの処理の中で一時的に利用するための変数であるため、関数の外からアクセスしようとするとエラーになります。

ローカル変数の挙動例

例えば、ある関数の中で `animal` という変数を定義して値を代入したとします。この関数を実行すれば問題なく動作しますが、関数の外で `print(animal)` と実行して中身を表示させようとしても、Pythonは「そんな名前の変数は定義されていません」という `NameError` を出します。

これは、関数の中で作られた変数が「ローカルな名前空間」に属しており、関数の処理が終わると同時にその寿命が尽きるためです。

グローバル変数:どこからでも見える共通変数

一方で、関数の外(プログラムのメイン部分)で定義された変数を「グローバル変数」と呼びます。

グローバル変数は、同一ファイル内のどこからでも参照できるのが特徴です。いわば「共有スペース」に置かれた道具のようなもので、関数の外はもちろん、関数の中からでもその値を読み取ることができます。

グローバル変数の参照

例えば、関数の外で `animal = 'ペガサス'` と定義しておけば、関数の中でその変数 `animal` を呼び出したとき、Pythonはまず関数内に同じ名前の変数がないか探し、なければ外側のグローバル変数を見つけ出してその値を表示してくれます。

このように、Pythonでは「関数内で変数を呼び出したとき、グローバルで定義されていればそれが使用される」という仕組みになっています。

【注意】関数内でグローバル変数を書き換える時の罠

ここで初心者が最もハマりやすいポイントがあります。それは、「関数の中からグローバル変数を書き換えようとしたとき」の挙動です。

単に値を「参照(読み取り)」するだけなら問題ありませんが、関数の中でその変数に新しい値を「代入(書き換え)」しようとすると、Pythonはそれを「新しいローカル変数を作ろうとしている」と判断します。

代入を行うとローカル扱いになる

例えば、グローバル変数がある状態で、関数の中で同じ名前の変数に値を代入する処理を書いたとします。このとき、Pythonは代入が行われた瞬間にその変数を「ローカルスコープ」として扱います。

もし、代入処理の前にその変数を参照しようとすると、「ローカル変数として扱うはずなのに、まだ値が入っていない」と判断され、例外(エラー)が発生することがあります。グローバル変数を上書きするつもりで代入処理を行うと、意図せずローカル変数として独立してしまい、外側のグローバル変数には影響を与えないという現象が起きます。

global文を使って明示的に書き換える

関数の中からグローバル変数の値を正しく更新したい場合は、`global` というキーワードを使います。

関数定義の直後で `global 変数名` と宣言することで、「この関数内で使うこの変数は、新しく作るローカル変数ではなく、外にあるグローバル変数のことですよ」とPythonに明示的に伝えることができます。

これにより、関数内部で行った代入処理がグローバル変数に反映され、関数が終わった後も更新された値が保持されるようになります。

Python特有のスコープの仕様:ブロックはスコープにならない

他のプログラミング言語(Javaなど)を学んだことがある人が驚くのが、Pythonの「ブロック」に関する仕様です。

多くの言語では、`if` 文や `for` 文、`while` 文などの `{ }` やインデントで囲まれたブロックの中で宣言した変数は、そのブロック内だけで有効(ブロックスコープ)になります。しかし、Pythonでは `if` や `for`、`while`、`try`、さらには `with` ブロックはスコープを形成しません。

つまり、`if` 文の中や `with` ブロックの中で定義した変数は、そのブロックを抜けた後でもそのまま参照することが可能です。

これは直感に反するため、他の言語を触っている人は「ブロックの外でも参照できているのはなぜか」と違和感を覚えることがありますが、Pythonの仕様としてはこれが正解です。

クラスとインスタンスにおけるスコープの注意点

スコープの概念は、クラスを扱う際にも現れます。

クラスに定義した変数をインスタンス内で再度代入する場合、値を代入することでスコープがインスタンス内に限定されます。メソッド内で代入処理を行うと、それはローカルスコープとして取り扱われるため、クラス変数として操作したい場合は、明示的にクラスを指定して操作する必要があります。

また、特に注意が必要なのが「Mutable(変更可能)な変数」の扱いです。 リストのようなMutableな変数の場合、代入処理(`=` による書き換え)が行われず、`append()` のように中身だけを変更する操作を行った場合は、グローバルスコープなどで処理されることがあります。

さらに、メソッドのキーワード引数にMutableな値を初期値として渡した場合、その初期値はクラスが呼ばれた後に一度しか評価されず、その後はグローバルスコープのように振る舞うという仕様があります。そのため、意図せず前回の呼び出し時のデータが残ってしまうという「罠」にハマることがあります。

まとめ:スコープと上手く付き合うために

Pythonのスコープを整理すると以下のようになります。

  • ローカル変数: 関数の中で定義され、その関数内でのみ有効。
  • グローバル変数: 関数の外で定義され、ファイル全体で参照可能。
  • global文: 関数の中からグローバル変数を書き換えたい時に使用する。
  • ブロックの仕様: `if` や `for`、`with` などのブロックは新しいスコープを作らない。

Pythonのスコープは、シンプルである反面、代入のタイミングやMutableな変数の扱いで曖昧な挙動に見えることがあります。

トラブルを防ぐためのポイントは、「変数の役割を明確にすること」です。 特にグローバル変数を多用すると、どこで値が書き換わったのか追跡しにくくなり、バグの原因になります。可能な限り関数に引数として値を渡し、結果を `return` で返す設計を心がけることで、スコープに起因するトラブルを減らすことができます。

また、クラス変数を取り扱う際は適切にクラスを指定し、Mutableな変数の初期化には細心の注意を払うことが、クリーンなコードへの近道となるでしょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次