こんにちは、ナナです。
ここまでに『変数』と『関数』に関して学んできましたが、この2つには関係性があります。
変数という情報を、関数という処理で制御するのが、プログラムの基本構造です。そのため、この2つの関係性を理解していないと、情報を正しく管理できません。
本記事では次の疑問点を解消する内容となっています。
では、『変数』と『関数』の関係性について学んでいきましょう。
『ローカル変数』と『グローバル変数』とは?
C言語でも出てきた『ローカル変数』と『グローバル変数』のことかしら?
Pythonにもあるのね。考え方は一緒なのかしら?
そうだね。『ローカル変数』と『グローバル変数』という情報の管理方法はプログラミング言語において必要な要素なんだね。だから、C言語でもPythonでも共に存在するよ。
それじゃあ、Pythonにおけるこの2つの変数の違いを改めて解説しようね。
どのプログラミング言語においても、この『ローカル変数』と『グローバル変数』というのはよく登場します。
この2つの違いを理解するためには、『関数』というものを理解して初めて違いが知ることができます。つまり、『関数』を学んだ今こそが、理解できる準備が整ったということです。
『ローカル変数』と『グローバル変数』の定義を見てみよう
それでは、この2つの定義の違いをプログラムで示しましょう。次のプログラムは、グローバル変数「x」とローカル変数「y」を定義したものです。
def print_y():
y = 100 # ローカル変数
print("y:", y)
x = 50 # グローバル変数
print("x:", x)
print_y()
x: 50
y: 100
結局、『グローバル変数』と『ローカル変数』というものの違いは何かというと、定義する場所の違いなのです。
このように関数ブロックで定義された変数のことを『ローカル変数』と呼び、関数の外側であるファイルで定義された変数のことを『グローバル変数』と呼びます。
この2つの変数は特性が異なるため、利用状況に合わせてどちらにするかを選択する必要があります。
この2つの違いは非常に大事なものです。順に解説しましょう。
『ローカル』と『グローバル』、この2つの変数の違いは、ものすっごい大事です。
定義された場所によって扱いが変わりますので、変数を見たときに「これはローカル変数だな」とか「この変数はグローバル変数だな」とかが判別できるようになっておく必要があります。
『ローカル変数』と『グローバル変数』のスコープの違い
変数でも『ローカル』と『グローバル』で扱いが変わるのね。まずは、スコープとやらが、どんな風に違うのか解説なさいっ!
世界をまたにかけるグローバルな人材のわたくしは、『グローバル』を応援するわよっ!
この2つは使い分けが大事なんですよ!
だから、どっちか一方に肩入れせずに、平等な目で見てあげてくださいね。それぞれにメリットがあるんですよ。
スコープとは、変数を参照できる範囲、つまり「利用できる範囲」のことです。
『ローカル変数』と『グローバル変数』では、スコープ範囲が決定的に違います。
ローカル変数のスコープ範囲
ローカル変数のスコープ範囲を示す、特徴的なプログラムと実行結果です。
def test_func():
y = 100 # ローカル変数
print("関数:", y)
print("ファイル:", y)
test_func()
print("ファイル:", y)
NameError: name 'y' is not defined
このように関数内で定義された変数「y」は関数の外からは見ることができません。つまり、『ローカル変数』のスコープは、所属する『関数』の中でのみ有効となります。
「ローカル」とは「局所的」という意味です。
つまり『ローカル変数』とは「関数の中だけで使える局所的な変数」ということになるんです。
グローバル変数のスコープ範囲
ローカルとは対照的に、グローバルとは「広域的」という意味になります。つまり、使える範囲が広がるということです。
具体的にプログラムと実行結果で示しましょう。
def test_func():
print("関数:", x)
x = 50 # グローバル変数
print("ファイル:", x)
test_func()
ファイル: 50
関数: 50
『グローバル変数』として定義された変数「x」は、関数の外側でも内側でも利用できるのがわかりますね。
これこそが広域的なスコープを持つ『グローバル変数』の特徴です。
『グローバル変数』は、ファイルの中のどの関数からも参照することができる便利なやつなんです!
それぞれのスコープのメリット・デメリット
一見すると参照範囲が広い『グローバル変数』は使い勝手がいいように思いますが、一概にそうは言えません。
『グローバル変数』は、参照範囲が広くなる分だけ扱いが難しくなります。
『グローバル変数』は様々な関数から見えるという便利さのメリットがあるものの、影響度が大きくちょっとした間違いが広範囲の問題となって拡散する性質もあります。
それに対して『ローカル変数』では、参照範囲が狭い特性を活かしたメリットがあります。
def test_func1():
y = 100 # ローカル変数
print("関数func1:", y)
def test_func2():
y = 200 # ローカル変数
print("関数func2:", y)
test_func1()
test_func2()
関数func1: 100
関数func2: 200
このように、異なる関数で定義された変数「y」は、それぞれ別の変数として存在することができます。
これはものすごく大きなメリットなんです。
システム全体で同一の変数名が使えなかったら、変数名を考える際に全体の中で重複しないことを保証しなければならなくなります。大規模な開発では、そんなことやってられません。
それではスコープの違いに関するメリット・デメリットをまとめましょう。
変数を参照できるスコープが異なる!
これは『グローバル』と『ローカル』の名に直結する代表的な違いですよ。
『ローカル変数』と『グローバル変数』の生存期間の違い
C言語においても同じようにスコープ範囲が違っていたのを思い出したわ。Pythonでも同じなのね。
じゃあ、次の「生存期間」とやらの違いを語ってごらんなさいっ!
C言語と同じでスコープの違いは分かりやすいね。
「生存期間」に関しては「変数を生き物のように捉える視点」が必要になるよ。じゃあ、解説するよ。
「生存期間」というと、生き物に対して「生きている期間」を示す言葉ですね。
変数は生き物ではないのですが、生き物のように見てあげることで「生存期間」というものが理解できます。
「変数」はメモリというハードウェアで生まれ亡くなっていく・・・
「変数」とは情報を記憶するための箱ですが、箱を生み出すことが「変数定義」というものです。
変数定義を行うことで、メモリ上に「変数」という箱が生まれるのです。
この箱があれば、様々な情報を記憶させておくことができます。しかし、この箱はいったいいつまでメモリの上に置かれ続けるのでしょうか?
これこそが変数の「生存期間」に関するテーマとなります。
ローカル変数の「生存期間」とは?
あらためて言いますが『ローカル変数』とは、とある関数に所属している変数です。
def test_func():
y = 100 # ローカル変数の定義
y += 100
print("y:", y) # 変数の活用
return # 生存期間終了
test_func()
y: 200
このような『ローカル変数』は変数定義により生み出され、関数がreturnすると共に亡くなっていきます。
生存期間が終わるということは、変数が記憶していた情報が消失することを意味します。
次のように関数を2回呼び出したときは、呼び出される度に変数「y」が生まれ、亡くなり、再度生まれ、亡くなってなっていきます。
def test_func():
y = 100 # ローカル変数の定義
y += 100
print("y:", y) # 変数の活用
return # 生存期間終了
# 関数を2回呼び出す
test_func()
test_func()
y: 200
y: 200
『ローカル変数』は名前は同じですが、時を経て別の変数として蘇っているのです。
生まれ直したときには、以前の記憶していた情報は全て忘れ去ってしまっていることに注意です。
生存期間が終わると変数が記憶していたものが消失する!これめちゃくちゃ大事なことです。
プログラミングで変数をうまく操れない人は、この「生存期間」を意識できておらず、情報をいつまで使えるのかを理解していません。
グローバル変数の「生存期間」とは?
『グローバル変数』は関数に所属せず、ファイルというものに所属しています。そのため、ローカル変数とは全く異なる「生存期間」を持っています。
def test_func1():
print("関数1:", x)
def test_func2():
print("関数2:", x)
x = 50 # グローバル変数の定義
print("ファイル1", x)
test_func1()
test_func2()
print("ファイル2", x)
ファイル1 50
関数1: 50
関数2: 50
ファイル2 50
このように『グローバル変数』は変数定義が行われてから、プログラムが終了するまで生存しています。
『ローカル変数』と違って、関数が終わっても変数の値を保持し続けることができるのが『グローバル変数』の特徴です。
『ローカル変数』は生存期間が終わると変数の中の情報は消失してしまいます。『グローバル変数』はプログラムが動いている間は生存しているので、実質的にずっと生存しているとも言えます。
グローバル変数を関数の中で書き換えるときに必要な「global宣言」について
グローバルに活躍する変数は、関数の外でも中でも自由に参照できるのね。わたくしと同じように大活躍な変数だわ!
グローバル変数をいろいろな関数から使ってあげるわよ!
ちょっと待ってー!ここまでのサンプルコードではグローバル変数を関数の中で値を見ることはあっても、書き換えている例を示していません。
実は、グローバル変数を関数の中で書き換えるときは、特別な宣言が必要になります。それが「global宣言」です。
Pythonでは『グローバル変数』を、関数の中から書き換えるときに限り「global宣言」が必要となります。
これはあまり他の言語にはない特徴です。
global宣言を使ったプログラム
プログラム例と実行結果を示しましょう。
def test_func():
global x # グローバル宣言
x = 200 # グローバル変数のxを書き換え
x = 50 # グローバル変数の定義
test_func()
print("x:", x)
x: 200
test_func関数の中で、『グローバル変数』の「x」を書き換えたい場合、このように「global宣言」を実施する必要があります。
global宣言の書式
global宣言の書式を明示しておきましょう。
global宣言の書式
global グローバル変数名
定義例
global x
global number
関数の中で『グローバル変数』を書き換えるときは、この宣言を事前に行っておく必要があることに注意が必要です。
global宣言を関数毎に行えば、共通のグローバル変数にアクセスすることも可能です。
def test_func1():
global x
x += 10
def test_func2():
global x
x += 20
x = 50 # グローバル変数の定義
test_func1()
test_func2()
print("x:", x)
x: 80
このようにグローバル変数にアクセスしたければ、関数毎に「global宣言」を行います。
『ローカル変数』と『グローバル変数』の使い分け
『ローカル変数』と『グローバル変数』は、「スコープ」と「生存期間」の違いがあるのね。
この2つは何を基準にどちらを使用するのかを選択するのかしら?
プログラミングを始めたばかりの人は、とりあえずスコープ範囲が広い『グローバル変数』を使いがちです。しかし、それはよくありません。
変数定義の基本は、まずは『ローカル変数』を基準として考えることです。
複数の関数から参照したいなど、『グローバル変数』を使わざる負えない場合に『グローバル変数』で対処するのが正しい考え方です。
ローカル変数は使い捨てが簡単にできる変数なんです。「使い捨てカイロ」とか、「使い捨て容器」とかって便利ですよね。
パッと使って忘れることができるというのが、『ローカル変数』の良さなんです。
変数も同じで一時的に使いたい用途では、使い捨てが可能な『ローカル変数』を使うのがよいのです。
Q&A:Pythonの「グローバル変数」「ローカル変数」に関するよくある質問
「変数」で何か質問ある人はどうぞ!
Q:グローバル変数は関数の中から見るだけなら「global宣言」が不要なのに、書き換えるときはなぜ必要なの?
あなたっ!どういうことなの?
グローバル変数の中身を見るだけなら「global宣言」なんてものがなくていいのに、書き換えるとなったら「global宣言」が必要って、意味が分からないわ!
論理的に説明できるんでしょうねっ!なんとなくじゃ納得いかないわよ。
そうなんですよ、不思議ですよねー。まぁそういうルールですから…。
ルールと言ってしまえば簡単なんですが、やはり論理的な理由があることで物事を理解することは大切なことです。
Pythonという言語を作った人にも、理由があってこのような言語仕様になっているわけです。
この理由に関しては『Python global宣言【書き換えの時に宣言が必要な理由】』にまとめてありますので、気になる方は是非見てください。
課題:「グローバル変数」の使い方が学べたかを確認しよう
もしも、プログラムが上手く動かなくて困ったときは、答えを見るのではなく「デバッガ」の使い方を学びましょう。
この記事を見ると問題の解決技術が身に付きます。困ったときのオススメ記事です!
課題1:グローバル変数で管理する情報
課題内容
次のプログラムをベースとし、func関数の呼び出し回数をprint関数を使って表示せよ。
def func():
# func関数の呼び出し処理(変更しない)
for i in range(10):
for k in range(20):
if k % 3 == 0:
func()
else:
func()
func()
func()
# func関数が呼び出された回数を表示せよ
print("呼び出された回数:")
画面の表示形式は出力期待値と同じとする。
出力期待結果
呼び出された回数: 340
『グローバル変数』をうまく活用すれば簡単に回数を数えることができます。
def func():
global count
count += 1
# 呼び出し回数を数えるグローバル変数
count = 0
# func関数の呼び出し処理(変更しない)
for i in range(10):
for k in range(20):
if k % 3 == 0:
func()
else:
func()
func()
func()
# func関数が呼び出された回数を表示せよ
print("呼び出された回数:", count)
関数を呼び出すよりも前に、count変数を定義しておかないと、エラーが発生することに注意しましょう。
「関数が呼ばれた回数を数える」ということは、関数の中で定義する『ローカル変数』では管理できません。
『グローバル変数』を定義し、関数が呼ばれる度にカウントアップすれば可能ですね。
C言語技術者が知るべきPython言語との違い:「グローバル変数」
すでにC言語を習得している人は、次のポイントに気を付けよう!
C言語技術者には見慣れない「global宣言」が特徴です。
このglobal宣言はC言語でいうと、ファイル間でグローバル変数を参照するための「extern宣言」に相当する役割を持っています。
Pythonでは関数の外側にある『グローバル変数を参照したい』という意味を込めて「global宣言」が必要となるのです。