抜粋翻訳 PEP227: Statically Nested Scopes

概要

このPEPは Python 2.2 への静的にネストしたスコープ(レキシカルスコープ)の追加と、Python 2.1へのソースレベルでのオプションについて記述する。また、 Python 2.1はこの機能がenableされた場合に意味が変わるような構造について警告をする。

従来の言語仕様(2.0以前)では、変数名を解決するのに用いる名前空間をちょうど3つ定義していた。ローカル、グローバル、そしてビルトインの名前空間である。ネストしたスコープの追加によって、未束縛のローカル変数名をそれを包む関数の名前空間で解決することが出来るようになる。

この変更によるもっとも分かりやすい結果は、無名関数(や他のネストした関数)が、それを取り囲む名前空間で定義された変数を参照できるようになることである。現在、無名関数では(訳注:外で定義された変数を)無名関数の名前空間に明示的に束縛するためにデフォルト引数を頻繁に使わなければいけない。

導入

この提案は、Pythonの関数の中の自由変数を解決する方法を変更する。新しい名前解決の動作は Python 2.2 から効果を発揮する。この動作は Python 2.1 でもモジュールに"from __future__ import nested_scopes"と付けることで利用可能である。(PEP 236を参照)

Python 2.0の仕様はそれぞれの名前を解決するのに、ちょうど3つの名前空間だけを定めていた。ローカル名前空間、グローバル名前空間、そしてビルトイン名前空間である。
この定義により、もしある関数Aが別の関数Bの中で定義されている場合、Bの中で束縛されている名前はAの中からは見ることができない。この提案はこのルールを変更し、Bの中で束縛された名前がAの中でも見えるようにしよう(ただしAがBの束縛を隠してしまうような名前束縛を含まない場合に限る)というものである。

この仕様はAlgol系の言語で普遍的なレキシカルスコープのルールを導入する。レキシカルスコープとすでにサポートされているファーストクラスの関数の組み合わせは、Schemeを連想させる。

変更されるスコープのルールには2つの問題があった。ラムダ式(と一般にネストした関数)の限られた機能、そしてネストしたレキシカルスコープをサポートしている他の言語に慣れた新規ユーザが頻繁に混乱すること、例えば再帰的な関数はモジュールレベルでしか定義できないことなど、である。

ラムダ式は一つの式だけを評価する名前のない関数を作る。これはよくコールバック関数として用いられる。下記の例(Python 2.0のルールを使って書かれている)では、ラムダの本体の中で使われている名前はすべて、明示的にラムダのデフォルト引数として渡さなければならない。

  from Tkinter import *
  root = Tk()
  Button(root, text="Click here",
         command=lambda root=root: root.test.configure(text="..."))

このアプローチはめんどくさい。特にいくつもの名前がラムダの中で使われる場合には。
デフォルト引数の長いリストはコードの目的を分かりにくくする。提案する方法では、ぶっきらぼうに言えば、デフォルト引数のアプローチを自動的に実装することでこの問題を解決する。この"root=root"という引数は削除できる。

新しい名前解決の動作は Python 2.0 と異なる振る舞いが原因でいくつかの問題を起こす。ある場合にはプログラムのコンパイルができなくなり、またある場合では以前はグローバルの名前空間で解決されていた名前が外側の関数のローカルの名前空間で解決されるようになる。Python 2.1では、異なる挙動をする文すべてについて警告が発せられる。