global宣言を行った変数は、どこで変数を定義すればよいのか? 2つの関数から同じ変数に対してglobal宣言を行ったときも、変数の変更が連動するのか? global宣言とnonlocal宣言は同じ関数の中で同時に行えるのか?などなど、疑問を検証してみました。
global宣言 とnonlocal宣言を簡単に説明すると「global宣言を関数の中で行うと、関数の内側からglobal変数を変更することができる。」「nonlocal宣言を関数の中で行うと、関数の内側から、外側の関数の変数を変更することができる。」ことです。
ただ、実際に使う前に、「こんな使い方をしたらどうなるの?」という疑問が、たくさん浮かんできましたので、検証しました。
0.チュートリアル学習のポイントシリーズ
この記事は「チュートリアル学習のポイントシリーズ」の記事です。一連の記事のリンクは、以下を参照してください。
Pythonチュートリアルの学習のポイントを整理
1.global宣言
global宣言を関数の中で行うと、関数の内側からglobal変数を変更することができます。それでは、global宣言について検証してみましょう。
(1) global宣言の基本的な使い方
まずは、基本的な使い方について検証します。コード01では、xxx1(),xxx2(),xxx3()が入れ子構造の関数になっています。そして、1番内側のxxx3()の中で変数xについて、8行目でglobal宣言を行っています。
変数xは、関数の外(2行目)だけではなく、すべての関数内で宣言(4, 6, 9行目)されていますので、xxx1(),xxx2()内のxはローカル変数です。したがって、2行目で宣言したglobal変数は、関数内のxには影響を与えません。しかし、xxx3()では変数xをglobal宣言しているので、global変数を変更することができます。出力01の8行目では、xxx1()実行前にはx = 0だった変数xが、x = 3に変更されています。
#コード01
x = 0
def xxx1():
x = 1
def xxx2():
x = 2
def xxx3():
global x
x = 3 #変更不能体の代入でも、global変数が連動して変更される。
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
print('xxx0:', x)
xxx1()
print('xxx0:', x)
#出力01
xxx0: 0
xxx1: 1
xxx2: 2
xxx3: 3
xxx2: 2
xxx1: 1
xxx0: 3 #変数xが0から3に変更されている
少しだけ、難しくします。コード02はコード01の4行目のx = 1を削除したものです。その場合、xxx2()ではコード01と同様にglobal変数の影響を受けませんが、関数xxx1()では変数xが定義されていないので、global変数の影響を受けるようになります。したがって出力02の3行目、7行目が出力01とは違う出力結果になります。
#コード02
x = 0
def xxx1():
#x = 1
def xxx2():
x = 2
def xxx3():
global x
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
print('xxx0:', x)
xxx1()
print('xxx0:', x)
#出力02
xxx0: 0
xxx1: 0 #コード01のときは1だった
xxx2: 2
xxx3: 3
xxx2: 2
xxx1: 3 #コード01のときは1だった
xxx0: 3
(2) 関数の外側にグローバル宣言を行った変数が定義されていない場合
コード01では、2行目で「x = 0」と変数xを定義していましたが、コード03では削除しました。つまり、コード03は、本来global変数を定義すべき位置でxの値を定義していません。しかし、エラーにはならず、コード01と同様の出力ができました。
このように、global変数を関数の外側で定義しなくても、global宣言により 関数の内側から定義することが可能です。
#コード03
#x = 0
def xxx1():
x = 1
def xxx2():
x = 2
def xxx3():
global x
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
xxx1()
print('xxx0:', x)
def yyy1():
x = 11
def yyy2():
global x
print('yyy2:',x)
yyy2()
yyy1() #xxx3()からの変数xの変更が、yyy2()にも反映される
#出力03
xxx1: 1
xxx2: 2
xxx3: 3
xxx2: 2
xxx1: 1
xxx0: 3
yyy1: 3
(3) 2つの別の関数内で同じ変数のglobal宣言をおこなった場合
コード03をもう一度見てみましょう。コード03では、xxx3()だけではなく、yyy2()の中でも変数xをglobal宣言しています。この場合、関数xxx3()内での変数xの変更が、yyy2()のxにも影響をあたえることがわかります。
2つの別の関数内で同じ変数xのglobal宣言をおこなった場合、global宣言を行った関数同士では、変数xが連動する共通の変数になります。
(4) 内側からだけではなく、外側からも変更できるのか
コード04は、コード03のあとに、「x = 4」「yyy1()」を追加しました。関数yyy1()の外側(29行目)での変更が、global宣言を行った関数yyy2()のxに影響を与えていることがわかります。
念のため検証を行いましたが、global変数ですので、関数の外側での変更がglobal宣言を行ったxxx3(), yyy2()内に影響を与えるのは当たり前の結果ではあります。
#コード04
def xxx1():
x = 1
def xxx2():
x = 2
def xxx3():
global x
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
xxx1()
print('xxx0:', x)
def yyy1():
x = 11
def yyy2():
global x
print('yyy2:',x)
yyy2()
yyy1() #xxx3()からの変数xの変更が、yyy2()にも反映される
x = 4
yyy1() #関数の外での変更も関数内に影響する
#出力04
xxx1: 1
xxx2: 2
xxx3: 3
xxx2: 2
xxx1: 1
xxx0: 3
yyy2: 3
yyy2: 4
(5) global宣言を行った変数はどこで定義すればよいのか
global宣言をおこなった変数は、どこで定義すればよいのでしょうか。ここでいう定義とは、実際に変数に値を代入し、変数の型などを決定することです。
コード05は、18行目のxxx1()の実行前にxの値を出力しようとしましたが、xが定義されていないというエラーが発生しました。xxx1()やyyy1()の外側のglobal変数xは、xxx1()を実行することによって、8行目で、はじめて変数が定義されます。変数が定義されなければ、変数の値がきまりませんので、出力することができずにエラーになります。「変数は実際にその変数を実行するまでに、変数の定義を行う」というのが原則です。
#コード05 →エラー
def xxx1():
x = 1
def xxx2():
x = 2
def xxx3():
global x
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
print('xxx0:', x) #変数xが未定義
xxx1()
print('xxx0:', x)
#出力05
NameError: name 'x' is not defined
コード06も同様に8行目で変数xが定義される前にxを出力しようとしたのでエラーになりました。
#コード06
def xxx1():
x = 1
def xxx2():
x = 2
def xxx3():
global x
print('xxx3:', x) #変数xが未定義
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
xxx1()
print('xxx0:', x)
(6) 関数内で変数を定義した後にglobal宣言することはできるのか
コード07は、7行目で x = 3と定義した直後(8行目)にglobal宣言を行ったのですが、「すでにxは宣言されている」というエラーになってしまいました。8行目でglobal宣言をするまえに7行目でx = 3としているので、global宣言する前にローカル変数として定義されてしまいました。変数xを定義する前(変数xに値を代入する前)にglobal宣言を行う必要があります。
#コード07 →エラー
def xxx1():
x = 1
def xxx2():
x = 2
def xxx3():
x = 3
global x #globalの宣言をする前にローカル変数として定義されている
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
xxx1()
print('xxx0:', x)
#出力07
SyntaxError: name 'x' is assigned to before global declaration
2.nonlocal宣言
nonlocal宣言を関数の中で行うと、関数の内側から、外側の関数の変数を変更することができます。以下、nonlocal宣言について検証します。
(1) 外側の関数が複数ある場合
それではnonlocalについても、まず、基本的な働きについて検証します。コード08では、xxx1(),xxx2(),xxx3()が入れ子構造の関数になっています。そして、1番内側のxxx3()の中で変数xについて、8行目でnonlocal宣言を行っています。
nonlocal宣言を関数の中で行うと、関数の内側から、外側の関数の変数を変更することができるようになりますが、xxx3()の外側には2つの関数xxx2(),xxx3()が存在します。このように外側に複数の関数がある場合には、内側から優先的に検索します。つまり、 nonlocal宣言を行ったxxx3()の変数xと、そのすぐ外側のxxx2()の変数xが連動する共通の変数になります。
#コード08
x = 0
def xxx1():
x = 1
def xxx2():
x = 2
def xxx3():
nonlocal x
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
print('xxx0:', x)
xxx1()
print('xxx0:', x)
#出力08
xxx0: 0
xxx1: 1
xxx2: 2
xxx3: 3
xxx2: 3 #すぐ外側の関数xxx2()のxの値が変更された
xxx1: 1
xxx0: 0
(2) すぐ外側の関数にnonlocal宣言された変数がない場合
すぐ外側の関数にnonlocal宣言された変数がない場合には、更に外側の関数に変数がないか検索されます。
コード09はコード08の6行目のx = 2を削除しました。最も内側の関数xxx3()でnonlocal宣言された変数xを9行目でx =3に変更すると、すぐ、外側のxxx2()に変数xが定義されていないか検索しますが、xxx2()ではxが定義されていないので、さらに外側のxxx1()の変数xがxxx3()の変数xと連動する共通の変数になります。
なお、関数xxx2()ではxが定義されていないので、xxx2()ではその外側のxxx1()のローカル変数xの影響をうけることになります。
つまり、xxx3()のxを変更すると、nonlocal宣言によって共通の変数となったxxx1()のxが変更されます。すると、xxx1()のローカル変数xの影響をうけるxxx2()においても、xの値が変わることになります。
#コード09
x = 0
def xxx1():
x = 1
def xxx2():
#x = 2
def xxx3():
nonlocal x
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
print('xxx0:', x)
xxx1()
print('xxx0:', x)
#出力09
xxx0: 0
xxx1: 1
xxx2: 1 #xを定義していないので、xxx1()のローカル変数の影響をうける。
xxx3: 3
xxx2: 3 #xxx3のxの変更でxxx1のxが変更。さらに、xxx1のxの変更でxxx2のxが変更
xxx1: 3 #nonlocal宣言によりXXX3のXの変更の影響を受ける。
xxx0: 0
(3) 外側の関数のどこにもnonlocal宣言された変数がない場合
外側の関数xxx1()、xxx2()のどちらにもnonlocal宣言された変数xがない場合はどうなるのでしょうか。結果はエラーになりました。入れ子構造の関数の完全に外側、つまり、global変数に同じ名前の変数があったとしても、その値は参照しません。
コード10では、nonlocal宣言を行ったxxx3()の外側の関数xxx1(), xxx2()では変数xが定義されていません。したがってエラーの結果となりました。2行目でglobal変数としてxが定義されていますが、nonlocal宣言では、global変数は参照できません。
#コード10 →エラー
x = 0
def xxx1():
#x = 1
def xxx2():
#x = 2
def xxx3():
nonlocal x
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
print('xxx0:', x)
xxx1()
print('xxx0:', x)
#出力10
SyntaxError: no binding for nonlocal 'x' found
3.global宣言とnonlocal宣言を同時に行えるのか
global宣言とnonlocal宣言は同時に行うことができません。コード11ののように、7行目でnonlocal、8行目でglobal宣言を行うとエラーになりました。
#コード02 →エラー
def xxx1():
x = 1
def xxx2():
x = 2
def xxx3():
nonlocal x
global x #nonlocalとglobalの宣言を重ねられない。
x = 3
print('xxx3:', x)
print('xxx2:', x)
xxx3()
print('xxx2:', x)
print('xxx1:', x)
xxx2()
print('xxx1:', x)
xxx1()
print('xxx0:', x)
#出力11
SyntaxError: name 'x' is nonlocal and global
4.参考記事
以上、global宣言とnonlocal宣言の使い方について検証した結果です。スコープや、の内容が分かっていなければ、理解しにくいと思いますので、以下の記事も参考にしてください。