結論: スコープは、**変数が「見える範囲」**のことです。**関数の中でつくった変数(ローカル変数)**は、その関数の中だけで使えます。関数の外の変数(グローバル変数)は、関数の中から読むことはできますが、書き換えると別の扱いになります。エラーが出た時は、NameError(見えない変数を使った)と、UnboundLocalError(外の変数を中で書き換えようとした)を疑ってください。
スコープとは
プログラムには、たくさんの変数が登場します。もし、すべての変数が、どこからでも見えて、書き換えられるとしたら、別々の場所で、同じ名前を使った時に、値が混ざってしまいます。
そこで、変数には、**使える範囲(スコープ)**が決められています。変数の基本は、変数とはをご覧ください。
ローカル変数とグローバル変数
| ローカル変数 | グローバル変数 | |
|---|---|---|
| つくる場所 | 関数の中 | 関数の外 |
| 使える範囲 | その関数の中だけ | プログラム全体 |
| 関数が終わると | 使えなくなる | 残る |
name = "田中" # グローバル変数
def greet():
count = 0 # ローカル変数
print(name) # 外の変数は、読める
print(count)
greet()
print(name) # OK
print(count) # NameError:関数の外からは、見えない
関数の基本は、関数とはで解説しています。
エラーの原因と直し方
① NameError
def f():
x = 1
f()
print(x)
# NameError: name 'x' is not defined
x は、関数の中だけで使える変数です。関数の外から使おうとすると、見えないため、エラーになります。
直し方:使いたい値は、return(戻り値)で、外へ渡します。
def f():
x = 1
return x
x = f()
print(x) # 1
② UnboundLocalError
count = 0
def add():
count = count + 1 # エラー
return count
add()
# UnboundLocalError: local variable 'count' referenced before assignment
関数の中で count = ... と代入すると、Pythonは、count をこの関数のローカル変数として扱います。右側の count は、まだ値がないローカル変数を読もうとするため、エラーになります。
直し方:外の値は、引数で渡し、結果を戻り値で返します。
def add(count):
return count + 1
count = 0
count = add(count)
print(count) # 1
globalキーワード
関数の中から、グローバル変数を書き換えたい時は、global を使うこともできます。
count = 0
def add():
global count
count = count + 1
ただし、おすすめしません。
- どこで値が変わるのか、追いにくくなる
- 関数が、外の状態に依存し、テストしにくくなる
- 思わぬ場所で値が変わり、バグの原因になりやすい
引数と戻り値で受け渡す書き方に、そろえるのが安全です。
ifやforの中でつくった変数
Pythonでは、if や for は、新しいスコープをつくりません。
for i in range(3):
last = i
print(last) # 2(ループの外でも、使える)
ループの変数 i も、ループが終わったあとに、使えます。条件分岐やループの基本は、条件分岐(if文)とはと、ループ(繰り返し)とはをご覧ください。
JavaScriptでは
言語によって、ルールが違います。JavaScriptでは、次のようになります。
| 書き方 | スコープ |
|---|---|
let / const |
波かっこ { } の中だけで使える(ブロックスコープ) |
var |
関数の中で使える(関数スコープ) |
let と const を使うのが、現在の一般的な書き方です。