初心者のためのpython入門

自分がつまづいたところやつまづきやすいところを中心に書いていきます。また、役に立つライブラリの紹介などをしていきます。

スコープと名前空間

スコープと名前空間

前回の説明の中で、スコープという言葉が出てきたと思います。今回は、そのスコープと名前空間について説明したいと思います。

スコープ

スコープとは簡単に言えば「変数が使用できる範囲」です。これは変数がプログラムのどこからでも好きなように使えるわけではない子を意味しています。全ての変数は、必ずいずれかのスコープに属することになります。そして、そのスコープは大きく分けると2種類になります。

  • モジュールのグローバルスコープ
  • 関数のローカルスコープ

グローバルスコープ

グローバルスコープは、最上位のスコープです。グローバルスコープで宣言された変数は同じモジュール(ファイル)内ならばどこからでも使用できます。

>>> scope = 'global'
>>> def print_global():
...      print('inside:', scope)
... 
>>> print_global()
inside: global
>>> print('top:', scope)
top: global

関数内でscope変数を参照できています。scope変数のようにグローバルなスコープを持つ変数をグローバル変数と呼びます。

ローカルスコープ

ローカルスコープは、関数内のスコープであり、関数が呼ばれるたびに生成されます。つまり、それぞれの関数ごとに固有のローカルスコープを持ちます。そのため、同じ関数であっても変数が共有されることはありません。

>>> def print_local():
...      scope_local = 'local'
...      print('inside:', scope_local)
...
>>> print_local()
inside: local
>>> print('top', scope_local)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'scope_local' is not defined

関数内で定義された変数をグローバルスコープからは参照できず、例外が発生します。scope_local変数のようにローカルなスコープを持つものをローカル変数と呼びます。

関数の中の関数のスコープ

入れ子構造(ネスト)になった関数のスコープはどうなるでしょうか。今回のサンプルはファイルを作成しています。

# sample.py
def parent():
    parent = 'parent'
    print("parent:", parent)

    def child():
        child = 'child'
        print("child:", parent)
        print("child:", child)

    child()
    # print("parent:", child)

parent()
# 実行結果 (python sample.py)
parent: parent
child: parent
child: child
# parent: <function parent.<locals>.child at 0x10b30ec80>

実行結果から、child()関数は親のローカル変数にアクセスできることがわかります。# print("parent:", child)の"#"を決して実行してみると、child()内で定義されたchild変数にアクセスできないことがわかります。

関数内でグローバル変数にアクセスする

関数内でグローバル変数を参照するには、"global"を使います。

# sample.py
scope1 = "global"
scope2 = "global"

def print_global():
    global scope1
    scope1 = "local"
    scope2 = "local"
    print("inside scope1:", scope1)
    print("inside scope2:", scope2)

print("top scope1:", scope1)
print("top scope2:", scope2)
print_global()
print("top scope1:", scope1)
print("top scope2:", scope2)
# 実行結果 (python sample.py)
top scope1: global
top scope2: global
inside scope1: local
inside scope2: local
top scope1: local
top scope2: global

globalを使うとグローバル変数にアクセスし、書き換えたりすことが可能となります。

ネストされ関数から親のローカル変数にアクセスする

関数内でグローバル変数にアクセスできるように、ネストされた関数で親のローカル変数にアクセスすることもできます。"nonlocal"を使います。

def parent():
    parent = 'parent'
    print("parent:", parent)

    def child():
        nonlocal parent
        parent= 'child'
        print("child:", parent)

    child()
    print("parent:", parent)

parent()
# 実行結果 (python sample.py)
parent: parent
child: child
parent: child

nonlocalを使う親関数のローカル変数にアクセスして、書き換えたりることが可能になります。

スコープの内容にアクセスする

Pythonにはスコープの内容にアクセスするための関数が2つあります。

  • globals(): グローバルスコープの内容を示す辞書を返す
  • locals(): ローカルスコープの内容を示す辞書を返す
# sample.py
scope = "global"

def print_global():
    scope = "local"
    print("locals:", locals())

print_global()
print("globals:", globals())
# 実行結果 (python sample.py)
locals: {'scope': 'local'}
globals: {'__name__': '__main__', 
          '__doc__': None, 
          '__package__': None, 
          '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x101c1c2b0>, 
          '__spec__': None, 
          '__annotations__': {}, 
          '__builtins__': <module 'builtins' (built-in)>, 
          '__file__': 'sample.py',
          '__cached__': None, 
          'scope': 'global', 
          'print_global': <function print_global at 0x101ba5e18>}

スコープのイメージ

イメージを載せておきます。

f:id:tiginkgo:20171210145539p:plain:w300

最後に

おつかれさまでした。