数弱の文系大学生によるブログです。

Python、Webデザイン関連の記事を投稿していけたらなと思っています。

備忘録的なブログなので、読みにくい文章だと思います。ご了承ください。

Python3の復習(名前空間とスコープ)

こんにちは。

かにたまごです。
昨日、一昨日と合宿で、Python3の復習とブログの更新ができませんでした。
ただ、今回の合宿では新しく学んだことが多かったので、その復習もいつか記事にしたいと思います。


さて、今回は

について、復習していきます。


今までのPython3 復習履歴は以下の通り。

  1. 数値・文字列
  2. リスト・タプル
  3. 辞書・集合
  4. if文・while文・for文
  5. 内包表記
  6. 関数
  7. ジェネレータ
  8. デコレータ

名前空間とスコープ

参考書籍の言葉を借りると

名前空間とは、特定の名前の意味が一意に決まり、ほかの名前空間の同じ名前とは無関係になる領域のこと

らしい。この一文で理解できたら苦労ないよね。


まず、僕なりに「名前」と「空間」の意味を考えてみると

名前 = 変数
空間 = アクセスが可能な場所

という結論に至りました。


そして最初の文を書き換えてみると

同名の変数であってもアクセス可能な場所が異なれば、それぞれの変数を特定できる領域のこと

という感じに。


うーん。全然まとまってない。
とりあえず先進みます。

プログラムのメイン部分(グローバル名前空間)で定義される変数をグローバル変数と呼ぶ。
対して、プログラムのサブ部分(関数内)で定義される変数をローカル変数と呼ぶ。

分かる人には分かるんだろうけど、僕は「ちょっと何言ってるかわかんないっす」状態。
圧倒的理解力のなさ。

  • スコープ

参考書籍にはスコープの説明が載ってなかった・・・。

調べてみたところ、トップにあったこちらの記事が参考になりました。

ものすごく簡潔にまとめると、ある変数を参照可能な範囲のことをスコープと呼ぶみたいです。

上に書いた空間と似ている・・・?

  • お決まりごと

グローバル変数とローカル変数に関するお決まりごとをまとめておく。


とりあえず言葉的な理解は置いておいて、コードで理解していこうかな。

#グローバル変数
global_variable = "私はグローバル変数ですよ"

def local_func():
    local_obj = global_variable
    print(local_obj)

出力 ->
私はグローバル変数ですよ

これは、ただ単にグローバル変数への参照がlocal_objに渡って出力されているだけ。
個々のオブジェクトに割り当てられるIDを確認するid関数で調べてみた結果。

#グローバル変数
global_variable = "私はグローバル変数ですよ"

def local_func():
    print(id(global_variable))
    local_obj = global_variable
    print(id(local_obj))

出力 ->
2535136
2535136

最初に述べた名前空間に関する僕なりの解釈を先に調べておく。


同名の変数であってもアクセス可能な場所が異なれば、それぞれの変数を特定できる領域のこと

この解釈に基づくと、グローバル変数とローカル変数はアクセス可能な場所が異なるので、それぞれを特定できるはず。

idol = "松田聖子"

def local_func():
    idol = "AKB48"
    print(idol)

#ローカルで定義されたidolが出力される
local_func()

出力 ->
AKB48


#グローバルで定義されたidolが出力される
print(idol)

出力 ->
松田聖子

こちらは成功。


グローバル変数を取得し、同名のローカル変数idolに代入してみる。

idol = "小泉今日子"

def local_func():
    #小泉今日子と乃木坂46が共演! を期待
    idol = idol+"と乃木坂46が共演!"
    print(idol)

local_func()
Traceback (most recent call last):
  File "C:\Users\***\Desktop\Python\Test\blog_test.py", line 583, in <module>
    local_func()
  File "C:\Users\***\Desktop\Python\Test\blog_test.py", line 580, in local_func
    idol = idol+"乃木坂46が共演!"
UnboundLocalError: local variable 'idol' referenced before assignment

このコードでは、左辺(idol)はローカル変数を想定していて、右辺(idol+"乃木坂46が共演!")のidolはグローバル変数を想定している。

しかし、結果はエラー。

この理由は、どちらがグローバル変数でどちらがローカル変数なのか分からないからだと思う。

分からないが故に、右辺のidolをローカル変数だと認識してしまって

「idolって変数(左辺のidol)を新たに定義しようとしているみたいだけど、まだ未定義のままだよ。未定義の変数(右辺のidol)を参照することはできないよ。」

ってエラーが出ているんだと思う。

エラー文を口語にしてみたけど合ってるかどうかは分からない・・・。


じゃあこの問題をどう解決するか。

一つは、単純にグローバル変数とローカル変数の名前を変えてあげる方法。

idol = "小泉今日子"

def local_func():
    #小泉今日子と乃木坂46が共演! を期待
    #アンダーバーを追加したidol_を定義
    idol_ = idol+"と乃木坂46が共演!"
    print(idol_)

local_func()

出力 ->
小泉今日子と乃木坂46が共演!

これで、どっちがグローバル変数でどっちがローカル変数かが区別できるようになる。


もう一つがお決まりごとに書いたglobalキーワードを使う方法。

このキーワードを使うことで、グローバル変数であることを明確化することができる。

idol = "薬師丸ひろ子"

def local_func():
    global idol
    #idol += "と乃木坂46が共演!"と書いても良い
    idol = idol+"と乃木坂46が共演!"
    print(idol)

local_func()

出力 ->
薬師丸ひろ子と乃木坂46が共演!

グローバル変数を参照してその中身を書き換えているので、グローバル名前空間にいるidolも当然書き換わっている。

idol = "薬師丸ひろ子"

def local_func():
    global idol
    #idol += "と乃木坂46が共演!"と書いても良い
    idol = idol+"と乃木坂46が共演!"
    print(id(idol))

local_func()
print(id(idol))
print(idol)

出力 ->
53487904
53487904
薬師丸ひろ子と乃木坂46が共演!


グローバル名前空間とローカル名前空間の確認には、それぞれglobals()locals()を使用する。

idol = "薬師丸ひろ子"

def local_func():
    global idol
    idol = idol+"と乃木坂46が共演!"
    print("local: ", locals())

local_func()

print("global: ", globals())

出力 ->
local:  {'local_idol': 'C-Style'}
global:  {'__name__': '__main__', '__doc__': None...(その他色々)}

ローカル名前空間には、ローカル変数として定義されたlocal_idolのみが存在している。
グローバル名前空間には、ローカル変数以外にも色々存在していることが分かる。

プログラミングに関することは言葉だけで理解しにくい、ということを痛感した復習時間でした。
改めてプログラミング力を向上させるには書きまくるしかないと思いましたね。頑張ろ。


以上です。


参考にさせていただいたサイト:

Python超入門その14〜意外と重要なスコープを理解しておこう〜