【python入門】pythonチュートリアルで詰まった点(nonlocal変数とglobal変数・スコープ)
こんにちは。
今回はpython3エンジニア基礎試験で詰まった点について記載します。
(nonlocal変数とglobal変数)
・名前空間とスコープ
python3チュートリアルの「クラス」の分野です。
チュートリアルに以下のような例文があります。
def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam) scope_test() print("In global scope:", spam)
結果
After local assignment: test spam・・・疑問① After nonlocal assignment: nonlocal spam After global assignment: nonlocal spam・・・疑問② In global scope: global spam
疑問①
do_local()の後の結果が"local spam"ではなく"test spam"
疑問②
do_global()の後の結果が"global spam"ではなく"nonlocal spam"
答えは、スコープにあるようです。
◾️スコープ
プログラムの有効範囲を示すもの
pythonのスコープはインデントで決まる
つまり、今回のチュートリアルのスコープはこうなっているようです。
疑問①
do_local()の後の結果が"local spam"ではなく"test spam"
検証結果
ローカル変数はlocalスコープ1内でのみ有効
試しにlocalスコープ1内でprintしてみた
def scope_test(): def do_local(): spam = "local spam" print("localスコープ1内のspam:",spam) #追加 def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam) scope_test() print("In global scope:", spam)
結果
localscope1内のspam: local spam #ローカルスコープ内ならlocal 変数を参照 After local assignment: test spam #別のローカルスコープになるため同じインデント(スコープ)の"test spam"を参照 After nonlocal assignment: nonlocal spam After global assignment: nonlocal spam In global scope: global spam
疑問②
do_global()の後の結果が"global spam"ではなく"nonlocal spam"
検証結果
nonlocal変数はインデントが同じ階層の別のローカルスコープ(local1,local2,local3,local)の中で、global変数より優先される
global変数はglobalスコープで適用される
試しにglobal変数を定義した関数を最初に呼び出し、そのあとにnonlocalを定義した関数を呼び出してみた
def scope_test(): def do_local(): spam = "local spam" def do_global(): #nonlocalより先に定義 global spam spam = "global spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" spam = "test spam" do_global() #nonlocalより先に呼び出し print("After global assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_local() #local変数を最後に呼び出し print("After local assignment:", spam) scope_test() print("In global scope:", spam)
結果
After global assignment: test spam #global変数を定義しているがlocalスコープの変数が優先された After nonlocal assignment: nonlocal spam After local assignment: nonlocal spam In global scope: global spam #globalスコープではglobal変数が適用される
(参考)
ちなみに、do_local()の中でdo_nonlocal()を定義すると、nonlocalの一つ外側のスコープであるdo_localのスコープ内ではnonlocalが優先され、2つ外側のスコープだとtest_spamになりました。
nonlocalは1つ外側のスコープまでなんですね。
def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): spam = "local spam1" #ローカル変数を定義 def do_nonlocal1(): #内側にnonlocalを定義 nonlocal spam spam = "nonlocal1 spam" do_nonlocal1() print ("nonlocalの1つ外側のスコープ",spam) def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam) scope_test() print("In global scope:", spam)
結果
After local assignment: test spam nonlocalの1つ外側のスコープ nonlocal1 spam After nonlocal assignment: test spam #nonlocalの2つ外側のスコープ After global assignment: test spam In global scope: global spam
スコープについてはこちらのサイト様が参考になりました。
またこちらのサイト様は色々検証されていて参考になります🙏