特集
» 2016年12月09日 05時00分 UPDATE

特集:Visual Studioで始めるPythonプログラミング:Pythonにおける名前空間とスコープを理解する上でのポイントを押さえよう (1/4)

簡単なコードを試しながら、Pythonの名前空間とスコープについての理解を深めよう。

[かわさきしんじ,Insider.NET編集部]
「特集:Visual Studioで始めるPythonプログラミング」のインデックス

連載目次

 前回はPythonのパッケージを取り上げた。今回はサンプルコードを実行しながらPythonのスコープの仕組みと名前空間について考えてみる。

ちょっとテスト

 まずは次のようなコードを対話環境で実行してみよう。ここではPython Tools for Visual Studio(以下、PTVS)の[Interactive]ウィンドウでも、コマンドプロンプトから起動した対話環境でも、Pythonに標準添付の統合環境「IDLE」でも何を使ってもよい。

l = list(range(1, 10))  # 組み込み関数listを使ってリストを作成
print(l)
list = 10               # 変数listに整数10を束縛
l = list(range(1, 10))  # これはエラーとなる


Pythonの挙動を試してみるコード(その1)

 実際に試してみると、結果は次のようになる。

>>> l = list(range(1, 10))
>>> print(l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list = 10
>>> l = list(range(1, 10))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable


最後の行でエラーが発生した

 当たり前のことだが、変数listに整数10を代入(束縛)したので、最後の行の「list(range(1, 10))」の呼び出しが失敗している(「TypeError: 'int' object is not callable」=「整数オブジェクトは呼び出し可能ではない」)。見た目的には「組み込み関数list」の定義を整数値で上書きしてしまったかのように見える。が、実はそうではない。続けて以下を試してみよう。del文は指定された名前を削除するものだ。

del list  # 名前listを削除
l = list(range(1, 10))  # 組み込み関数listが再度呼び出し可能になる
print(l)


Pythonの挙動を試してみるコード(その2)

 実行結果を以下に示す。

>>> del list
>>> l = list(range(1, 10))
>>> print(l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]


組み込み関数listが呼び出せるようになった

 つまり、これは組み込み関数listの定義が上書きされたのではなく、ローカルに定義された変数listでそれが隠蔽(いんぺい)されたということだ。筆者もサンプルコードで「list = ……」とやってしまうことがあるので上のコードを例としたが、Pythonのスコープの仕組みにより、このようなことが起こるのだ。

 大ざっぱにいうと、Pythonのスコープには次のような種類があると考えてよい

  1. ローカルスコープ
  2. ローカルスコープを囲むスコープ(enclosing scope)
  3. (モジュールレベルの)グローバルスコープ
  4. 組み込み名前空間を表すスコープ

 ローカルスコープとはもちろん現在実行しているコードを含む最小範囲のブロックのこと。ただし、気を付けたいのは、PythonはC#などの言語ほど細かくはスコープを生成しない。大まかには関数定義やクラス定義は新たなスコープを生成するが、if文やfor文などではスコープは生成されない。そのため、例えば以下のようなコードはPythonでは正しいコードとなる。

def test(x):
  if x > 60:
    msg = "pass"
  else:
    msg = "fail"
  print(msg)  # if文を抜けてもmsgは生きている


Pythonではこれは正しいコード

 また、現在のローカルスコープを囲むスコープが存在している場合、それらは2のローカルスコープを囲むスコープ(enclosing scope)として扱われる。典型的には関数定義内での関数定義がそうだ。この場合、外側の関数のスコープは内側の関数のスコープを囲むスコープとなる。

 Pythonでは単独のファイルが単独のモジュールとなることは以前にも説明した通りだが、モジュールのトップレベルで定義される名前はモジュールレベルでグローバルなスコープに含まれる(同時に、それらはモジュールのトップレベルでローカルな名前ともなる)。

 最後の組み込み名前空間とは、Pythonに組み込みの関数やクラスなどを参照するために使われる名前空間のことだ(通常は変数__builtins__を利用して参照可能)。

 Pythonで名前(整数、関数、クラスなどを参照するラベル=変数)を参照する際にはこれらのスコープが先に示した箇条書きの上から順に検索されていく。よって、ローカルスコープで定義されている名前があれば、それが参照されるし、グローバルなスコープまで検索しても名前が見つからなければ、組み込み名前空間から名前が検索され、そこにもなければ例外(NameError)が発生するということだ。

 先ほどの例であれば、次の図のようになる。

Pythonのスコープと名前解決の順序 Pythonのスコープと名前解決の順序

 Pythonでは対話環境で実行されるコードは「__main__」モジュールに含まれる。また、上の例では対話環境でそのまま変数listを定義した(整数値10に名前listを束縛した)ので、名前listは__main__モジュールのローカルスコープかつモジュール内でグローバルなスコープに存在している。そして、その後の「l = list(range(1, 10))」行ではローカルスコープに存在する名前listが見つかるので、組み込み名前空間に含まれている名前listは検索されないことになる。次の例で示した「del list」文によりローカルスコープに存在していた名前listがなくなると、今度は組み込み名前空間に含まれる名前listが参照されるようになる。というのが一連の流れだ。

 何となくPythonのスコープの仕組みが分かったところで、次にPythonのスコープと名前空間についてもう少し深く探ってみよう。

       1|2|3|4 次のページへ

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。