【Python】変数の有効範囲(スコープ)

【Python】変数の有効範囲(スコープ)

コードが長くなってくると変数もたくさん必要になってくるため変数名を決めるのが難しくなってきます。変数名が重複すると値が上書きされてしまうため、プログラムが思うように動作しなくなってしまうことがあるためです。

これを避けるためにPythonをはじめとする多くのプログラミング言語では変数の有効範囲(スコープ)が決まっています。スコープは関数定義やループ処理を使いこなすために重要ですのでしっかり把握しておきましょう。

目次

スコープとは

Pythonでは関数定義の中と外は完全に独立したコードとして扱われます。

次のコードではattack関数の中と外でそれぞれadという同じ名前の変数が定義されています。

ad = 100 # 関数定義の外で定義されているad変数
skill = 2

def attack():
    ad = 200 # 関数定義の中で定義されているad変数
    damage = ad * skill
    print("勇者は" + str(damage) + "のダメージを与えた")
attack() # attack関数を実行
print("勇者は" + str(ad * skill) + "のダメージを与えた")

このコードを実行してみましょう。結果は次のとおりです。

勇者は400のダメージを与えた
勇者は200のダメージを与えた

1行目はattack関数の実行結果、2行目は同じ処理をprint関数で実行した結果です。

このコードではad変数が2つ定義されていますが関数定義の中と外ではスコープが分かれているため、attack関数の中のad変数と外のad変数は独立した別の変数として扱われています。attack関数の中ではad変数の値は200、外ではad変数の値は100となっているわけです。

このようにスコープがあれば関数定義の中で使う変数名については、関数定義の外側で定義されている変数名を気にせず付けることができます。

Pythonの変数はスコープにによって4つのタイプに分けられます。

Local ローカル変数

関数ブロックの中で定義された変数です。

def attack():
    ad = 200 # ローカル変数
    damage = ad * skill

その関数の中だけがスコープとなるため関数の中でのみ機能し、関数ブロックの外で呼び出すことはできません。

Enclosign Local エンクロージング関数ローカル変数

ローカル変数の中でも関数の外側で定義されている変数です。

例えばattack関数の中にdamage関数とad変数が定義されている場合、ad変数はローカル変数ではありますが、damage関数からみて外側で定義されています。

def attack():
    ad = 200 # エンクロージング関数ローカル変数
    def damage():
        skill = 3 # ローカル変数
        return ad * skill
    print("勇者は" + str(damage()) + "のダメージを与えた")

多くの場合単にローカル変数と呼ばれ、かつもっとも複雑なスコープのため覚える必要性は薄いです。

Global グローバル変数

ファイルのトップレベルで定義されている変数です。

ad = 100 # グローバル変数
skill = 2 # グローバル変数

def attack():
    ad = 200 # ローカル変数
    damage = ad * skill

グローバル変数のスコープはそのファイル全体です。特別な宣言をしなくても関数内で同じ名前の変数を使用することでグローバル変数として使用することができます。

Built – in 組み込み関数の変数名

print関数やlen 関数、range 関数などPythonの組み込み関数に用いられている変数名です。

print("hello world") # 組み込み関数の変数名

組み込み関数で使われている名前を変数の名前として使ってしまうと変数として定義されてしまい、その組み込み関数を使おうとしたときにエラーになってしまうので注意しましょう。

例として次のようなコードを用意しました。

print = 100
print("hello world")

このコードを実行すると次のようになります。

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    print("hello world")
TypeError: 'int' object is not callable

printという名前で変数を定義してしまったために、組み込み関数であるprint関数を呼び出すことができなくなってしまいました。

こうしたエラーを防ぐために、組み込み関数と被りそうな変数名を使うときは先にprint(関数名)を実行して確認しておきましょう。

global宣言

前述の通りPythonでは関数定義の中にある変数と外にある変数は独立した別の変数として扱われます。グローバル変数を関数内で呼び出すことはできますが、変数の中身を変更することはできません。

例えば次のコードを実行すると

ad = 100 # ad変数(グローバル)を定義
skill = 2

def attack():
    ad += 1 # ad変数(ローカル)に1加えるという処理になるが、ad変数(ローカル)は定義されていない
    damage = ad * skill
    print("勇者は" + str(damage) + "のダメージを与えた")

attack()

次のようにエラーになってしまいます。

Traceback (most recent call last):
  File "C:\Users\User\Desktop\python_lessons\test.py", line 9, in <module>
    attack()
  File "C:\Users\User\Desktop\python_lessons\test.py", line 5, in attack
    ad += 1 # ad変数(ローカル)に1加えるという処理になるが、ad変数(ローカル) は定義されていない
UnboundLocalError: local variable 'ad' referenced before assignment

定義されていないad変数(ローカル)に「1を加える」という処理をしようとしているためです。

関数内で処理が完結する場合は問題ないのですが、これでは関数の処理でグローバル変数を書き換えることができません。そんな時はglobal宣言をすることで、関数内でグローバル変数を扱うことができるようになります。

次のようにグローバル変数として扱いたい変数を、関数定義の中でglobalに続けて記述します。

ad = 100 # ad変数(グローバル)を定義
skill = 2

def attack():
    global ad # global宣言
    ad += 1 # ad変数(グローバル)に1加える
    damage = ad * skill
    print("勇者は" + str(damage) + "のダメージを与えた")

attack()
print("勇者は" + str(ad * skill) + "のダメージを与えた")

実行結果は次のようになります。

勇者は202のダメージを与えた

ad変数(グローバル)に1を加えて処理を無事実行することができました。

global宣言をした変数はグローバル変数として扱われるため、ad変数(グローバル)の中身そのものが書き換えられます。

ローカル変数を扱う場合と異なりプログラム全体に影響を及ぼす可能性があるため留意しておきましょう。

このエントリーをはてなブックマークに追加

コメントを残す

頂いたコメントは一読した後表示させて頂いております。
反映まで数日かかる場合もございますがご了承下さい。