2009年4月30日木曜日

整数の割り算の問題

原文:http://python-history.blogspot.com/2009/03/problem-with-integer-division.html
原文投稿者:Guido van Rossum

Pythonの整数の割り算は、初期の間違いが、とてつもなく大きな結果引き起こすという一つの例である。前に書いた記事で触れたが、Pythonは設計時に、ABCで使用されてきた数値の処理方法とは違う方法を採用している。例えば、ABCでは2つの整数の割り算を行うと、正確な有理数で表された結果が返された。しかし、Pythonでは整数の割り算を行うと、整数に丸められた結果が返される。

私の経験上、有理数を返すという方法は、ABCの設計者が期待したほどは成功しなかった。シンプルなビジネスアプリケーションのプログラム(税金の計算)を行ったときのに遭遇した事象が典型的な例である。期待していたよりもずっと処理速度が遅かったのである。デバッグをしたときに内部では何千桁もの精度の有理数の数値が使われていたということに気づいた。しかし、最終的な結果は、有効数字が2桁か3桁に丸められて出力されるのである。この問題は、不正確なゼロ(inexact zero)を追加し始めることで簡単に修正することができたが、直感的とは言えないため初心者にはデバッグするのが困難である。

そのため、Pythonでは、ABCとは異なる、私が慣れ親しんでいたC言語に沿った数値のモデルに頼ることにした。C言語では、整数と浮動小数点数の両方で、さまざまなサイズが存在する。そこで私はPythonの整数の表現にはC言語のlong(少なくとも32ビットの長さは保証される)を利用し、浮動小数点数の表現はC言語のdoubleを利用することにした。また、私が"long"と呼ぶ、任意精度の整数型も追加した。

数値に関する大きな間違いは、高級言語ではなく、C言語に近いルールを採用してしまったことにある。例えば、割り算を含む、標準の数値演算子の結果は、計算に使用したのと同じ型が常に返るようにした。私は最初は、これとはまた別の間違ったルールを使用していた。それは、数値の型を混ぜて使うのを禁止したことである。このルールは型の実装をお互いに独立させるのを目的としていた。そのため、最初のPythonでは、int型にfloat型を足すこともできなかったし、int型とlong型を足すのもできなかったのである。そのため、Pythonが一般向けにリリースされた直後に、Tim Peters氏から、このルールは本当に悪い考え方であるということを納得させられ、通常の型強制ルールに従って数値型を混ぜて計算するモードを導入することになった。例えば、int型とlong型が混ぜて使用された場合には、引数の型をint型からlong型に変換し、計算結果はlong型を返す。また、float型が使用された場合には、int型やlong型の引数はfloat型に変換し、結果はfloat型で返すようになったのである。

しかし、整数の割り算の結果が整数になるというダメージは残っていたのである。もしかしたら「なぜこのことがそんなに悪いことなのか?」と思う方もいるかもしれない。何も問題がないのに、ただ騒いでいるだけなのか?と。歴史的には、この仕様を変更しようとすると、昔から強く反対する人々が必ず現れてきた。彼らは、数値の割り算を学ぶことは、すべてのプログラマが「通過する儀式」であると信じているのである。そのような方もいるため、なぜこの設計がバグであるかと考えている理由を説明していこうと思う。

もし、例えば、月の満ち欠けの計算などである数値計算を行う関数を実装していたとしよう。通常なら、引数として浮動小数点数を指定したいと思うだろう。しかし、Pythonでは型宣言がないため、呼び出し側が整数の引数を渡して呼び出すことを妨げることはできない。C言語のような静的な型を持つ言語であれば、コンパイラが強制的に型変換をしてfloatにするが、Pythonではそのようなことはない。数値を混ぜるルールによって中間結果がfloat型に変換されるまでは整数型で計算されることになる。

割り算以外の演算子の場合は、整数は浮動小数点数と同じ振る舞いをする。例えば、1 + 1は2になるし、1.0 + 1.0は2.0になる。そのため、引数が整数か浮動小数点数かに関わらず、数値計算のアルゴリズムが問題なく動作するという誤解が簡単に生じてしまうのである。しかし、計算に割り算が含まれていて、入力される数値が両方とも整数になる場合には、暗黙のうちに結果の切り捨てが発生する。そのため、計算結果に大きな問題が入り込む可能性が本質的に含まれるのである。すべての引数を入力の時点で浮動小数点数に変換するという防衛的なコードを書くのも面倒な作業であるし、コードの可読性とメンテナンス性を下げることになる。かなり特殊なケースではあるが、それに加え、同じアルゴリズムに対して、複素数を入力して計算することを妨げることにもなってしまうのである。

繰り返すと、Pythonが、宣言された型への引数の型変換を自動的に行わないのが問題の原因である。例えば、文字列のような適切でない引数が渡されると、掛け算以外の演算は文字列と数値を混合して扱うことができないため、すぐに問題の発生が特定できる。しかし、浮動小数点数が期待されているアルゴリズムに整数が渡された場合には、正解に近いがエラーを含む結果を返すことになる。中途半端に正確なため、デバッグをしたり、問題に気づくのが難しいのである。最近、アナログ時計を描くプログラムで、切り捨てのために針の位置の計算がおかしくなるという問題が発生した。しかし、一日に何回かしか問題に気づくことはできなかった。

整数の割り算を修正するのは簡単なタスクではない。というのも、整数の割り算の結果が整数になるというのを期待して作成されたプログラムもあるからである。今までの割り算と同じ機能を提供する演算子(//)もPythonに追加された。それに加え、新しい整数の割り算の機能を追加する("from __future__ import division")というメカニズムも提供され、使用できるようになっている。振る舞いを変更し、プログラムの変換の手助けをするコマンドラインフラグの(-Qxx)が提供されている。さらに幸運なことに、この正しい振る舞いは、Python3000では標準的な動作となるのである。

なぜ、例外がクラス化されたのか?

原文:http://python-history.blogspot.com/2009/03/how-exceptions-came-to-be-classes.html
原文投稿者:Guido van Rossum

初期のころから、私はPythonでエラーを扱うために例外を使用したいと思っていたことを覚えている。しかし、例外を動作させるために重要なことは、異なる例外の種類を識別させるのにはどのような分類方法を利用すればいいのかというのを思いつくことである。現代的な言語は(もちろん最近のPythonも:-)、ユーザ定義クラスを使用して例外を定義する。しかし、初期のPythonはそうではなく、文字列によって例外を識別する方法が選ばれた。この選択は失敗ではあったが、この方法を選択した理由は2つあった。まず最初に、私は例外をModula-3で学んだが、この言語では例外というのは、重複のないトークンが使用されていたからである。2つめの理由としては、ユーザ定義クラスが導入される前に例外を導入したことである。

理屈の上では、私が例外のために組み込みのオブジェクトの新しい型を作るということも考えられたが、すべての組み込みオブジェクトの型はC言語上で努力してかなりの量のコーディングを行う必要があるので、私は既存の組み込み型を再利用する方を選択した。例外はエラーメッセージと結びつけられることがあるので、例外を表現するのに文字列を使用するのは自然なことであると思われた。

後から考えると失敗だったのだが、私は、異なる文字列オブジェクトが異なる例外を表現する、というやり方を選択してしまった。例え同じ内容の文字列(同じ文字の並びが含まれている文字列という意味)であっても、違うものとして認識されてしまうのである。このやり方を選択した理由としては、異なるモジュールで定義された例外は、例え同じ内容の文字列であっても、独立してそれぞれ違う例外であると区別できた方がいいだろう、と思ったからである。この考え方は、例外は常に名前(中身ではなくて変数名)で参照され、オブジェクトの同一性で判断されるだろう、との判断からである。値の一致性で見るためには文字列の中身の同一性をみる必要があるが、これを行うことはないと考えていたのである。

この方法はModula-3の例外からの影響を受けていた。Modula-3では、例外宣言があると、重複のない「例外トークン」が作られ、他の例外トークンと区別がつかなくなることはない。私は、ポインタを使って例外を比較するように最適化を行い、文字列の値の比較をなくして、実行時間を最適化しようという間違った誘惑にかられてしまった。これは珍しいケースである。私はいつも自分のコーディング時にしか最適化を行わないのだから。もっとも大きな理由は、異なるモジュールで定義された関係のない例外の名前が衝突してしまう、ということを心配したからである。このため、私は例外を使用するやり方を厳密に決める必要がある、と考えていた。まず例外をグローバルの定数としてモジュール内に定義をして、例外を上げたり、受け取ったりするときには、そのグローバル定数の名前を利用するというものである。これは、文字列リテラルが自動的に隔離するようになる、ずっと前のことである。

訳注:文字列の隔離というのは、同じ内容の文字列はメモリを共有して同じIDを持つように最適化することである。

悲しいことに、読者の方々の想像通り、実際にはこの方法はうまくいかなかった。初期のPythonユーザによって、同じ内容の文字列が合った場合に、同じモジュール内ではバイトコードコンパイラが統合してしまうことが発見された。これは、同じ文字列の値を持つ文字列リテラルがいくつも現れると、共有オブジェクトを一つだけ作る、ということである。この不具合により、例外は文字列の名前でも、エラーメッセージを含む文字リテラルの中身でも、同じように捕まえられることが判明したのである。実際には、同じモジュールの中で定義されたコードでのみ動作し、異なるモジュールの例外エラーメッセージを使って例外をキャッチしようとしても、不思議な失敗の仕方をしてしまうのである。言うまでもなく、これは広範囲にわたって混乱を発生させることになってしまった。

1997年のPython 1.5において、私は言語にクラス例外を導入した。Python 2.5まではレガシーアプリケーションをサポートするという目的で、文字列例外も残されてはいたが、クラス例外が推奨されることとなった。そして、Python 2.6において、最終的に文字列例外は姿を消したのである。

どのようにして、すべてが実行可能文になったのか?

原文:http://python-history.blogspot.com/2009/03/how-everything-became-executable.html
原文投稿者:Guido van Rossum

新しくPythonユーザになった人の中には、関数やクラスの定義まで含めて言語のすべてが実行可能文であるということを知って驚く人がいる。これは、あらゆるコードがプログラムのどこにでも現れることがある、ということを意味している。書こうと思えば、例えば"if"文の中に関数の定義を書くことも可能である。

最初の頃のバージョンのPythonの文法ではこのようにはなっていなかった。文法要素には「宣言フレーバー」と言うものがあり、import文や関数宣言などに使用されていた。これはその効果を使用したいと思うモジュールやスクリプトのトップレベルにしか置くことはできなかった。しかし、クラスのサポートを追加したときに、この文法は制限が多すぎると考えるようになった。

私の頭の中ではおおまかに以下のように推論していった。一連の関数宣言のみを使ってクラス本体の定義をするよりも、通常の変数割り当てをクラスの中で行った方がシンプルで道理に合っているだろう。しかし、これを許すのであれば、なぜもう一歩進めて、任意のコードの実行を許さないのだろうか?もしくは、さらに進めて、例えば"if"文の中に関数宣言を置くというようなことを認めてもいいのではないか?これを許可すると、文法をシンプルにすることができると即座に閃いた。インデントされているか否かにかかわらず、現在ある使用している文法と同じルールを共有することも可能である。そして、これらの文法を実現するのには、通常のコンパイラと同じバイトコードジェネレータ機能が利用できることが分かった。

この推論によって文法はシンプルになり、ユーザはPythonのコードをどこにでも書けるようになった。しかし、この機能は特定のプログラミングのスタイルのために必要だったというわけではない。例えば、Pythonではスコープのネストはサポートされていないが、技術的には関数宣言をネストするようなことも可能であった。そのような機能を念頭にいれてきちんと設計された言語と比べると、未定義な操作や、壊れた操作を引き起こす可能性もある。時間をかけて、多くのこれらの「壊れた」機能は修正されてきた。例えば、Python2.1以降は、ネストされた関数定義もきちんと動作するようになった。

すべてをファーストクラスに

原文:http://python-history.blogspot.com/2009/02/first-class-everything.html
原文投稿者:Guido van Rossum

Pythonにおける私の目標の一つが、すべてのオブジェクトを「ファーストクラス」にするというものであった。これは、プログラミング言語の中のすべてのオブジェクト(数値、文字列、関数、クラス、モジュール、メソッドなど)に対して、名前をつけて、同じように取り扱うことができるようになるということを意味している。オブジェクトを変数に格納したり、リストの中に並べたり、辞書に格納したり、引数として渡したり、といったことが可能になるのである。

これを実現するためのPythonの内部実装はとてもシンプルになっている。すべてのPythonのオブジェクトは共通のC言語の構造体を元にしており、インタプリタ内のあらゆる場所で使用されている。変数やリスト、関数などは、このデータ構造のバリエーションを利用している。数値のようなシンプルなオブジェクトを表現しようとしたり、クラスのような複雑なものを実現しようとしないかぎり、この手法で大きな問題は発生しない。

「すべてをファーストクラスに」という考えを持つことは概念としてはシンプルであるが、一つだけクラスにまつわる取り扱わなければならない微妙な問題が存在する。それは、メソッドをファーストクラスオブジェクトにするという問題である。

以下のようなシンプルなPythonのクラスがあったとする(先週のブログからコピーしてきた)。

class A:
     def __init__(self,x):
         self.x = x
     def spam(self,y):
        print self.x, y

もしメソッドがファーストクラスオブジェクトであった場合は、Pythonの中の他のオブジェクトと同様に、他の変数に割り当てることが可能になるだろう。例えば、"s = A.spam"というようなPythonのコードを書くことが可能になる。この場合、変数"s"はこのクラスのメソッドを参照しているが、これは関数そのものである。しかし、メソッドは通常の関数とは完全に同じではない。特に、メソッドの最初の引数は、メソッドが定義されたクラスのインスタンスが必ず入るという想定になっている部分が異なる。

この問題を取り扱うために、「非拘束メソッド(unbound method)」というものを作成した。非拘束メソッドは、メソッドを実装している関数オブジェクトを包む薄いラッパーである。このラッパーは最初の引数がメソッドが定義されたクラスのインスタンスになるという制限を加える。もし誰かが非拘束メソッド"s"を関数のように呼び出そうとした場合には、クラス"A"のインスタンスが最初の引数として渡されなければならない。サンプルを示すと、"a = A(); s(a)" という感じになる。

関連する問題が、オブジェクトの特定のインスタンスに関連づけられたメソッドを参照するようなPythonのコードを書いたときに発生する。例えば、誰かが"a = A()"のようにインスタンスを作成し、その後"s = a.spam"と書いたとする。このとき、変数"s"クラスのメソッドを参照しているが、この参照はインスタンス"a"を通じて得られたものである。このような状況を扱うために、「束縛メソッド(bound method)」と呼ばれる、また別の呼び出し可能なオブジェクトを使用することになった。このオブジェクトもまた、メソッドの関数オブジェクトを包む薄いラッパーになっている。このラッパーは裏で、メソッドを取得するのに使用した元のインスタンスを保持している。この後のコードで"s()"と呼ぶと、暗黙のうちに最初の引数にインスタンス"a"をセットしてメソッドを呼び出す。

実際には、束縛メソッドも、非束縛メソッドも同じオブジェクトを内部で使用している。このオブジェクトは、インスタンスへの参照を保持する属性を一つ持つ。この属性がNoneにセットされていると非束縛メソッドになり、そうでない場合には束縛メソッドになるのである。

束縛メソッドと非束縛メソッドなどはそれほど重要な問題には見えないかもしれないが、これらはクラスの動作の裏側を支える重要な部分である。プログラムの中で"s.spam()"というコードが出てくると、この文は実際には2ステップに分けられて実行される。まずは"s.spam"のメソッドの検索が実行される。この検索の結果、束縛メソッドである呼び出し可能オブジェクトが返される。その次に関数呼び出し演算子である"()"がこのオブジェクトに適用され、ユーザの指定した引数も渡されてメソッドが実行されるのである。


(*)Python3000では、非束縛メソッドの考え方が削除され、"A.spam"という式は、通常の関数オブジェクトを返すようになった。結局、最初の引数をAのインスタンスの限定しても、問題の分析の役に立つことはあまりない、ということになったのである。逆に高度な使い方を使用とした場合に邪魔になることも多かったからである。この高度な使い方というのは「duck typing self」という適切な名前で呼ばれている。

ユーザ定義クラスのサポートの追加

原文:http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html
原文投稿者:Guido van Rossum

にわかには信じられない人もいると思うが、CWIで開発が行われていた最初の一年の間、Pythonはクラスをサポートしておらず、最初の公開リリースの前にオブジェクト指向をサポートするようになった。どのようにクラスが追加されたかという過去の経緯を理解してもらう手助けになると思うので、現在のPythonがどのようにクラスをサポートしているのか、という点から話を始めようと思う。

Pythonはオーソドックスなスタックベースのバイトコードインタプリタ、もしくは仮想マシンとしてC言語で実装されている。プリミティブな型も同様にC言語で実装されている。アーキテクチャとしては一貫して「オブジェクト」を使用しているが、C言語はこのオブジェクトを直接サポートする仕組みを持っていない。そのため、構造体と関数ポインタを使用してこれらの仕組みが実装されている。Pythonの仮想マシンでは、すべてのオブジェクトの型がなるべく実装すべき演算子と、絶対に実装すべき演算子が何十個か定義されている。例えば「属性の取得」、「足し算を行う」、「関数の呼び出し」などである。オブジェクトの型は静的に確保された構造体として表現される。この構造体には標準的な演算子に関する関数のポインタが一式格納されている。ほとんどの場合は、これらの関数は静的な関数への参照で初期化される。いくつかオプションの演算子があるが、この関数ポインタをNULLのままにしておくことで、これを実装しないでおくことが可能である。実装されていないオプションを使った演算を行ってしまうと、実行時にエラーを生成するか、場合によってはデフォルトで実装されている演算子が代わりに使用される。Pythonの型の構造体にはさまざまなデータフィールドを格納することができ、このクラス固有の追加のメソッドへの参照も格納することもできる。この場合は、文字列(メソッド名)と関数ポインタ(実装)の配列として構造体の中に格納される。Pythonではイントロスペクションを行えるが、これは、実行時には他の要素と同様に、型構造体そのものもオブジェクトとして使用することができるようになっていることで実現されているのである。

実装における重要な側面は、これらの機能の実装がすべて、C言語を中心に実装されているということである。実際、標準の演算子やメソッドはすべてC言語の関数で使って実装されている。もともと、バイトコードインタプリタはピュアPythonの関数と、C言語で作成されたメソッドや関数を呼び出す機能しかサポートしていないのである。私の記憶が正しければ、PythonでもC++のようなクラス定義を追加して、Pythonでオブジェクトを作成する機能を追加したほうがいい、とアドバイスをしてくれたのは、私の同僚だったSiebren van der Zee氏が最初であった。

ユーザ定義のオブジェクトを実装するにあたり、私はなるべくシンプルな設計をとった。「クラスオブジェクト」への参照ポインタと、「インスタンス辞書」と呼ばれる辞書が格納できる、新しい種類の組み込みオブジェクトを用意した。これを使用することで、ユーザ定義のオブジェクトを表現するという仕組みになった。クラスオブジェクトは同じクラスに属するすべてのインスタンスで共有される。インスタンス辞書はインスタンス変数を格納する。

この実装では、それぞれのオブジェクトごとのインスタンス変数はインスタンス辞書に格納され、同じクラスのすべてのインスタンスで共有する要素や、特にメソッドは、クラスオブジェクトに格納される。クラスオブジェクトの実装においても、できるだけシンプルな実装を選択した。クラスのメソッドは、メソッド名をキーとする辞書に格納された。私はこれをクラス辞書と呼んでいた。継承をサポートするためにクラスオブジェクトには、ベースクラスに関連するクラスオブジェクト群への参照を追加した。その当時、私はあまりクラスには詳しくなかったが、その当時のC++が多重継承をサポートしたことについては知っていた。私は、継承をサポートするからには、単純なバージョンの多重継承をサポートした方がいいと考えた。このようにして、すべてのクラスオブジェクトはひとつ以上のベースクラスを持つことができるようになった。

このPythonのクラスの実装では、オブジェクトの裏側で動作しているメカニズムはとてもシンプルになっている。インスタンス変数やクラス変数が変更されると、裏側にある辞書オブジェクトに変更が反映されるという仕組みになっている。例えば、インスタンス上にインスタンス変数に値を設定すると、そのオブジェクトが持っている、ローカルのインスタンス辞書が更新されるのである。同様に、オブジェクトのインスタンス変数の値を見にいくときは、変数がその中に定義されているかどうか、そのオブジェクトのインスタンス辞書をただチェックするだけである。もし変数がその辞書の中にないとすると、少しだけ面白いことが発生する。この場合は、インスタンス辞書の次にクラス辞書の中の探索が行われ、それでも見つからなければ、ベースクラスのクラス辞書が順番に探索されていく。

このようなクラスオブジェクトとベースクラスの中を属性探索していくプロセスは、メソッドの場所を探索するのとほぼ一緒である。少し前に説明したように、同じクラスに属すすべてのインスタンスが共有しているクラスオブジェクトがあり、その辞書の中にメソッドが格納されている。メソッドが必要なときには、当然それぞれのオブジェクトが持つインスタンス辞書の中は探索しないだろう。その代わりに、まずクラス辞書の中を調べ、その後はメソッドが見つかって止まるまで、順番にベースクラスを見ていく必要がある。それぞれのベースクラスでは、同じ再帰的なアルゴリズムが実装されている。これは深さ優先、左から右へのルールと呼ばれている。これがほとんどのPythonのバージョンで用いられているデフォルトのメソッド解決順序(MRO)である。もっと新しい現在のリリースではより洗練されたMROを採用しているが、これについてはこれについては別の機会に話をしたいと思う。

クラスを実装する際に私が目標の一つとしていたのは、シンプルさを維持する、ということである。そのため、Pythonはメソッドを定義する時には事前のエラーチェックや整合性のチェックは行うことはない。もし、あるクラスが、ベースクラスで定義されているメソッドをオーバーライドした場合、再定義されたメソッドの引数の数は同一であるか、もしくは、オリジナルのベースクラスのメソッドと同じ呼び方ができるか、などのチェックが行われることはない。上記のメソッド解決順序のアルゴリズムは、ユーザが指定した引数がどんなものであっても、最初に見つけたメソッドを返し、その引数を渡してメソッドを呼び出すだけである。

このような設計を行ったが、この仕様の想定外の使われ方をしている機能も他にいくつか存在する。例えば、クラス辞書は当初、メソッドを置く場所として想定していたが、メソッドと同じように他の種類のオブジェクトを格納してはいけないという理由もなかった。そのため、数値や文字列といったオブジェクトをクラス辞書の中に定義したとすると、これらはクラス変数と呼ばれるものになるのである。通常の変数はそれぞれのインスタンスごとにデータを格納するが、これとは異なり、クラス変数はそのクラスの全インスタンス間で共有される変数となるのである。

Pythonのクラスの実装はシンプルであるが、驚くほどの柔軟さを備えている。実際に、実行時に簡単に中の情報を調べることができるという「ファーストクラスオブジェクト」だけを作成するような実装にはなっていないが、クラスを動的に変更することも可能である。例えば、クラスオブジェクトが作成された後であっても、クラス辞書を更新するだけで、メソッドを追加したり、変更したりすることができる。(*)Pythonの動的な性質が意味するところは、クラスのすべてのインスタンス、クラスのすべてのインスタンスそのサブクラスという単位で、すぐにこれらの変更が引き起こされるのである。同様に、それぞれのオブジェクトもまた、動的に追加したり、変更したり、インスタンス変数を削除することができる。Pythonのオブジェクトの実装が完了した後に知ったのだが、Smalltalkでは属性の追加はオブジェクト作成時に定義する時にのみ限定されているため、Pythonの実装はSmalltalkよりも自由である。

classシンタックスの作成

ユーザ定義のクラスやインスタンスの実行時の表現が設計できたので、次のタスクは、クラス定義の文法を設計することである。具体的に言うと、メソッド定義もこれに含まれる。私が関数のシンタックスとは異なるメソッド用のシンタックスを追加したくない、と考えていたことが設計上の主な制約であった。似ているが微妙に異なるようなケースを扱うために文法とバイトコードジェネレータをリファクタリングするというのは、とても大きな仕事のように感じていたからである。しかし、例えば文法を同じにすることに成功したとしても、その次にはインスタンス変数を取り扱う方法を考え出す必要がある。当初は、C++のような、暗黙のインスタンス変数をエミュレートできないかと期待した。例えば、C++では、以下のようなコードでクラスを定義する。

class A {
public:
   int x;
   void spam(int y) {
        printf("%d %d\n", x, y);
   }
};

このクラスではインスタンス変数xが定義されている。メソッドの中では暗黙的に、該当するインスタンス変数を参照しに行くことになる。例えば、spam()メソッドの中では、変数xは、関数のパラメータとして定義されたわけでも、ローカル変数として定義されているわけでもないため、クラスはxという名前を持つインスタンス変数であると断定するのである。そこで初めてxへの参照が、インスタンス変数と結びつけられるのである。私は当初は同じようなやり方をPythonの中でも提供できれば、と期待していた。しかしすぐに、変数宣言がない言語においては、インスタンス変数とローカル変数をエレガントに識別する方法が存在しないということが分かった。

理論的にはインスタンス変数の値を取得するの難しくはない。Pythonは既に、ローカル、グローバル、組み込みと、宣言のない変数名から順番に探索する機能を備えているからである。これらはすべて、名前をキーにした辞書にマッピングされて実装されている。変数参照ごとに、結果が見つかるまで、これらの辞書を順番に探索する。例えば、ローカル変数pと、グローバル変数qを持つ関数を実行していたとする。例えば、"print p, q"という文を実行する場合は、pはローカルなので、検索順序の最初にある、ローカル変数を格納している辞書を探索しただけで見つかる。変数qは最初の辞書の中には見つからず、グローバル変数を格納している2番目の辞書の中で見つかることになる。

メソッドの実行時に、メソッド検索リストの先頭に現在のオブジェクトのインスタンス辞書を追加するのは簡単な作業である。インスタンス変数xと、ローカル変数yを使用した、オブジェクトのメソッドの中で、"print x, y"があれば、検索過程の1番目にあるインスタンス辞書から変数xを見つけることは可能である。変数yは2番目の辞書であるローカル変数辞書の中にある。

この戦略の問題は、これがインスタンス変数の設定をぼろぼろにしてしまうというところにある。Pythonの変数割り当てでは、これらの辞書の中の変数名まで見にいくことはせずに、検索順の最初の辞書内の要素(通常はローカル変数)に関して単純に変数を追加したり変更したりしている。この仕組みがあるので、変数を定義すると、デフォルトではローカルスコープ内に作成されることになる。Pythonには「グローバル宣言」というものがあるが、これは関数や変数ごとのこの基本の動作を上書きして、グローバルスコープに変数を作成するために必要となる。

割り当てに関するこの単純なやり方をそのままにして、インスタンス辞書を検索順序の最初の順序においてしまうと、メソッド内でローカル変数を割り当てるのが不可能になってしまうことになる。以下のようなメソッドがあったとする。

def spam(y):
    x = 1
    y = 2

変数xとyの割り当ては、xに関してはインスタンス変数xの定義の上書きになり、ローカル変数のコピーとなるインスタンス変数yが作成されることになる。インスタンス変数とローカル変数の検索順序を交換したとすると、単に問題がひっくり返るだけである。結果としてインスタンス変数に割り当てることが不可能になるのである。

インスタンス変数がすでに存在している場合のインスタンス変数への割り当て方を変更すると、今度はローカル変数への操作がうまく行かなくなってしまい、結果としてブートストラップ問題になってしまう。どのようにしてインスタンス変数を初期化時に作成すればいいのだろうか?可能な解決策の一つとして、グローバル変数と同様に、インスタンス変数についても明示的に宣言しなければならない、とすることもできるだろう。しかし、こうしてしまうと、すべての変数の宣言が必要となってしまうため、私はこれを選択したいとは思わなかった。加えて、グローバル変数であると示すためには仕様を追加する必要があったが、グローバル変数に限って言えば、使う場面はほとんど特殊なケースのみで、ほとんどのコードでは慎重に使われている、という事情もある。インスタンス変数のための特別な仕様が必要ということになると、このグローバル変数の状況とは異なり、クラス内のあらゆるところで使用されることが前提となる。もう一つとりうる解決策としては、文法的にインスタンス変数とローカル変数の区別をきちんと行うようにする、というものもある。例えば、Rubyが現在取っているアプローチのように、すべてのインスタンス変数の名前を、@のような特殊文字で始まるようにしてしまうというものである。あるいは、特殊な命名規則をつけるとか、大文字小文字のルールを決めるというのもあるだろう。しかし、私はこれらの選択肢はどれも魅力的には感じなかったし、今も感じていない。

最終的に、私はインスタンス変数への参照を曖昧なままにするというアイディアをあきらめることにした。C++のような言語はthis->fooと明示的にインスタンス変数fooへの参照を書くことが可能である。このようにして書くことで、同名のローカル変数fooと区別することができるのである。そうして、私はインスタンス変数への参照方法を、このような明示的なやり方に限定することにした。加えて、私は現在のオブジェクトを示す、"this"のような特殊なキーワードを作成する代わりに、"this"あるいはそれと同等なものを、メソッドの最初の引数の名前から取ることにした。こうして、インスタンス変数はこの引数の属性として参照できるようになった。

このように明示的な参照をするようにしたため、メソッドの定義のために特別な文法を作成する必要もなくなったし、変数の検索のための複雑な仕組みについて悩む必要もなくなった。実際には、プログラマは、単純に最初の引数として、インスタンスが入る引数をつけて関数を作成するだけである。Pythonでは、この変数の名前として、"self"を慣例的に使用している。サンプルコードは以下のようになる。

def spam(self,y):
    print self.x, y

この方法は、私がModula-3で見た何かと似ている。私は既にModula-3のimportと例外ハンドリングの文法を参考にさせてもらっている。Modula-3はクラスは持っていないが、関数ポインタをメンバーとして持っているレコード型を作成することが可能である。関数ポインタメンバーは近くに定義されている関数であるかのように初期化される。メンバーの呼び出しへのシンタックスシュガーも追加される。例えば、xをレコードの変数、mを関数fに初期化されているレコードの関数ポインタメンバーであったとすると、x.m(args)の呼び出しは、f(x, args)と同等になる。この仕様は、典型的なオブジェクトとメソッドの実装と同じであり、Python同様に、最初の引数の属性と、インスタンス変数を同一視することが可能になる。

Pythonのクラスの文法の残りの部分は、これまで説明した仕様に従って決定されたり、他の実装によって課せられた制約によって決定された。class文も、シンプルにするという私の願望を維持するため一連のメソッド定義からなると考えたが、この慣習とは異なる実装になった。最初の引数が"self"という名前にする必要があるが、関数の定義とメソッドの定義は瓜二つな実装とした。それに加えて、特殊な種類のクラスのメソッド(コンストラクタやデストラクタなど)については、新しい仕様を考え出す代わりに、これらの機能はユーザが単純に特殊な名前(__init__や、__del__など)でメソッドを実装することで扱えるようにした。C言語の、アンダースコアから始まる識別子の名前はコンパイラの予約語であり、例えばC言語のプリプロセッサで展開される__FILE__などのように特殊な意味を持っていることが多いが、Pythonの特殊なメソッドの名前の規則はそのC言語を元にしている。

この結果、私が考えていたクラス定義のコードは以下のようなものになった。

class A:
     def __init__(self,x):
         self.x = x
     def spam(self,y):
        print self.x, y

何度も繰り返すが、私は、事前に作成したコードを、なるべく多く再利用したいと思っていた。Pythonにおける関数定義は、関数オブジェクトへの参照を、現在の名前空間内の中の変数にセットする実行文である。このときの変数名は関数名が利用される。そして、クラスの扱いについて違うアプローチが思い浮かんだが、単純に新しい名前空間の中で実行される一連の文としてクラスの本体を解釈するのが良いと考えた。この新しい名前空間は保存され、クラス辞書を初期化してクラスオブジェクトを作成するのに使用される。採用された実装方法は、まずクラスの本体を無名関数に入れ、この無名関数はクラスの本体の中のすべての文を実行し、ローカル変数の辞書を結果として返す。この辞書はクラスオブジェクトを作成するヘルパー関数に渡される。最後に、このクラスオブジェクトは現在のスコープの中の変数に格納される。この時、クラス名が変数名として使用される。無名関数として実行されるため、クラスの本体の宣言中に文法的に正しいPythonの実行文は何でも入れられるのであるが、これを知って驚くユーザは多い。この機能は、使いやすさを犠牲にしない範囲で文法をなるべくシンプルにしたいという私の希望を率直に拡張した結果生まれたものである。

最後に、クラスのインスタンス作成の文法について説明したいと思う。C++やJavaのような多くの言語は、新しいクラスのインスタンスを作成するのに、"new"といった特殊な演算子を使用する。C++のパーサの中ではクラス名はどちらかというと、特殊な状態として扱われるため、このようなことが可能になっている。Pythonの場合はクラスも単に変数に格納されたクラスオブジェクトでしかないため、特別扱いされることはない。Pythonのパーサは、関数呼び出しがあったとしても、どのような種類のオブジェクトかということに関しては無関心なので、私はすぐにクラスオブジェクトを呼び出し可能なものとして作成するのが良いと思った。既にある関数呼び出しという機能を利用することで、新しい文法が不要となり、最小限の手間で実現できるからである。。頭の中の時間を今日まで戻すと、最近はインスタンス生成のパターンとしてファクトリー関数というものが好んで頻繁に使用される。私がPythonに組み込んできた機能はまさに、クラスをそれぞれのファクトリー関数に転換するというものであった。

特殊メソッド

クラスの実装に関連する最後のセクションとして、私が主な目標としている、クラス実装をシンプルにするということに関して簡単に触れたいと思う。ほとんどのオブジェクト指向言語には、クラスに対してのみ適用されるような、特殊な演算子とメソッドが存在する。例えば、C++ではコンストラクタとデストラクタ専用の特殊な文法が存在し、通常の関数やメソッドを定義するために使用される通常の文法と異なっている。

私はオブジェクトが特殊な演算子を扱うのに、特殊な文法は導入したくないと思っていた。そのため、「特殊メソッド」として、__init__や__del__のような名前を事前に設定して、特殊な演算子とこの名前をマッピングすることによって扱えるようにした。これらの名前を定義することによって、ユーザはオブジェクトの構築と破棄に関連するコードが実装できるようになったのである。

私はこのテクニックをユーザのクラスに適用することによって、Pythonの演算子を再定義できるようにした。前に触れたとおり、PythonではC言語を使い、組み込みオブジェクトの機能(例えば、「属性の追加」、「足し算を行う」、「関数の呼び出し」など)を実装するために関数ポインタのテーブルを用いている。これらの機能をユーザ定義クラスの中で定義するために、様々な関数ポインタと、__getattr__, __add__, __call__といった特殊なメソッド名のマッピングをおこなった。新しいPythonオブジェクトをC言語で実装するときには、これらの名前と関数ポインタのテーブルの間の関連を定義する必要があるのである。


(*) 最終的に、新スタイルクラスはクラスの__dict__の変更を制御するためにこれが必要であった。現在も動的に変更することはできるが、クラスの__dict__を直接操作するのではなく、属性割り当てを使用すべきである。

2009年4月28日火曜日

Pythonの動的型システム

原文:http://python-history.blogspot.com/2009/02/pythons-use-of-dynamic-typing.html
原文投稿者:Guido van Rossum

ABCとPythonが大きく異なるのは、型システムに対する基本的な姿勢である。ABCは静的な型付けを採用している。ABCコンパイラは常にプログラムの中の型の使われ方を分析し、どのように使用されているのか分析を行う。もしうまく分析できないときは、そのプログラムは拒絶され、処理が実行されることはない。 当時の他の静的な型を持つ言語とは異なり、C言語のように明示的な型宣言をさせる代わりに、ABCは型推論を行っていた。ただし、Haskellとは似てなかった。それとは対照的に、Pythonでは動的な型システムを採用している。Pythonコンパイラは、型がどのようにプログラムの中で使用されるかという点には無関心である。型のチェックはすべて実行時に行われるのである。

これはABCから遠く離れた仕様のように見えるかもしれないが、読者の方々が思ったほどの違いはない。他の静的な型を持つ言語とは異なり、ABCは静的な型チェックだけに頼って、プログラムをクラッシュから守ろうとしているわけではないからだ(<-現在からすると歴史的なことなので過去形を使ったほうがよかったかも:-)。ランタイムライブラリは実行されるたびに、引数の型がどのように操作できるかというチェックをすべて行っていた。これはコンパイラと同じ型チェックアルゴリズムを使い、健全かどうかのチェックの一部として行われていたのである。初期の言語実装の中では、このチェックアルゴリズムの完全な実装は行われていなかった。ランタイムライブラリが明示的に実行時の型チェックを行い、わかりやすいエラーメッセージを出してくれたため、ライブラリ自体がデバッグを手助けしてくれたのである。この機能は実装チーム向けに整備された。そのため、引数を間違って指定したために、未チェックの何かの操作が行われて、インタプリタがどこかに行ってしまってコアダンプする、ということは起きなかったのである。

しかし、ABCが静的な型のチェックに加えて、実行時にも型のチェックを行っていた本当の理由は別にある。それはABCがインタラクティブな実行を許容していたからである。インタラクティブなセッションの中では、ユーザがABCの文や宣言を入力し、入力が完了したらその場で実行される。インタラクティブセッションでは、数値型として変数を作ったり、それを消したり、文字列型として再作成(言い方を変えると、別の変数を同じ名前で作成)したり、といったことが可能であった。一連の手続きの中で再作成した場合には、最初に数値型で変数を作成し、その次に同名の変数を文字列型として作成すると、静的な型エラーが検知されることが期待されるだろう。しかしインタラクティブセッションの中では、文を越えて型チェックを強制させられて、再作成が禁止されてしまうと都合が悪いことがある。もし間違って変数xを数値型で作ってしまうと、変数xを別の型で作成することができなくなってしまうからである。双方を考慮して妥協した結果、ABCはグローバル変数のチェックには動的な型チェックを使用するが、ローカル変数に対しては静的な型チェックを使用するというところに落ち着いた。Pythonではこれをさらにシンプルに実装して、ローカル変数に対しても動的な型チェックを行うようにしたのである。

そのため、Pythonの型チェックのアプローチと、ABCが実装したアプローチは、実際にはそれほど大きな差はないのである。Pythonはシンプルに、コンパイル時の型チェックを完全になくした。型に関するすべてのエラーは実行時に捕まえられるため、Pythonインタプリタが動作停止させられることはない。実行時だけのチェックであっても、最終的な動作の安全には悪い影響を与えることはないのである。これはPythonの「うまく手を抜く」という設計哲学にきちんと合っていると言えるだろう。

しかし、一度でも動的な型システムを使おうとすると、もう戻ることはできなくなってしまうだろう。ABCの組み込みの演算子は、演算の形式を見て型を推測できるように、慎重に設計されていた。例えば、ABCのコンパイラは、"x ^ y"という形の式から、コンパイラは変数xとyは文字列であり、演算結果も同様に文字列であるということを推測を行う。Pythonではもはやこのような推測を、一般化して実装することは不可能である。例えば、"x + y"という式は文字列の結合にも使用できるし、数値の足し算にも使用できる。また、Pythonでは、自分で定義した型に対して、自分でオーバーロードして演算子の動作を書き換えることもできるからである。

2009年4月27日月曜日

初期の言語設計と開発

原文:http://python-history.blogspot.com/2009/02/early-language-design-and-development.html
原文投稿者:Guido van Rossum

ABCからPythonへ

Pythonの開発のスタート時から、もっとも大きい影響を与えた言語は、1980年代の初め頃にLambert Meetens氏とLeo Geurts氏などがCWIで言語設計を行ったABCである。ABCはBASICの代替の教育用言語を目指していた言語である。そしてパーソナルコンピュータのための言語および環境になることを目指した。ABCの開発は、最初にプログラミングのタスクを分析する作業から始まり、何度か大きなユーザテストを含むイテレーションを実行しながら、言語の設計が行われた。私がABCグループで持った役割というのは、主にこの言語本体と、統合編集環境の実装である。

Pythonがインデントをブロックの区切りに使うようになったのは、ABCからの直接もらってきたアイディアであるが、元々はこの考え方はABCから生まれたものではない。これはすでにDonald Knuth氏によって推奨されるようになっていたし、プログラミングのスタイルとしてよく知られていた。また、occamというプログラミング言語が既にインデントを採用していた。しかし、ABCの設計者は、節とインデントされたブロックとを区別するのにコロンを使用することを思いついた。コロンがないバージョンでの初期のユーザテストにおいて、プログラミングの最初の一歩を教わっている初心者にとって、インデントの意味があまり明快には区別できていないということが分かったからである。コロンの追加により、コロンの前後で何がどうつながっているのかということに注意が向けられるようになり、かなり明確に理解されるようになったのである。

いくつか修正があるものの、Pythonの主なデータ型もABCから取り入れられた。ABCの配列はバッグか、もしくはマルチセットのどちらかであり、改良されたB-tree実装を使って常にソートされるようになっていた。ABCのテーブルも、キーによって常にソートされているような連想配列である。私はどちらのデータ型も、私が予想するような一般的な使用方法にはそぐわないと考えた。例えば、ファイルから読み込んだ行の配列を表現する場合などである。ABCでは行番号をキーとするようなテーブルを使用する必要があり、行の挿入と削除が極めて困難であった。そこで、私はリスト型を、挿入と削除の操作が簡単にできるような柔軟なデータ型に変更し、リスト内の項目の順序に関しては、ユーザがすべてコントロールできるようにした。ソートされた結果が必要な時があれば、そのときだけsortメソッドがそれをサポートするという仕組みにしたのである。

私は、ソート済みテーブルの実装も、ハッシュテーブルの実装に置き換えた。私がハッシュテーブルを選択した理由は、ABCのB-treeを使った実装よりも早く、簡単であると信じていたからである。後に、理論上でB-treeの方がスペースの消費量も、消費時間も、多くの操作領域で優れているということが分かったが、実際はB-treeアルゴリズムがあまりにも複雑なため、正しく実装するのが困難であると判断した。同じ理由から、小さいテーブルサイズのときのパフォーマンスも、部分最適化を行った。

ABCのタプル型(変更できない配列)はそのまま残した。Pythonの変数やりとりの際のパック/アンパックできるようにする、という操作はABCから直接もらったアイディアである。タプルが配列の内部表現として使われるようになると、私は配列のようなインデックスとスライスの操作をタプルに加えた。

配列のようなインタフェースをタプルに追加した結果、長さが0か1という境界条件のタプルをどのように扱えばよいかを決める必要が発生した。ABCから持ってきたルールのひとつに「すべてのデータ型は、画面に表示されるか文字列に変換するときには、言語のパーサーが正しく受け取れる表現で出力されるべきである」というものがある。そのため、これに従うためには、長さが0と1のタプルの場合には何か目印を付ける必要があるのである。しかし、だからといって、1要素のタプルと、カッコなしの数式表現の違いをなくしたくはなかった。最終的には、不恰好ではあるが、現実的なアプローチとして, 1要素でカンマが後ろについている場合には要素数1タプルになり、"()"の場合には要素数がゼロのタプルになる、という表現を採用した。Pythonの通常のカッコの表現は、この問題を除けばタプルの文法で必要とされるものに対して、すべてそのまま同じである。空のタプルが「何もない」と表現されるため、単純なタイプ間違いがあれば容易に発見できるはずである。

訳注:ここで言っている「要素数が0か1のタプル」というのは、数式の中では 4 - (1 + 2) 4 - (3) 4 - 3と、項目数がひとつだけのカッコは処理の過程で外されることになるが、データ構造としての要素数1のタプルにおいて、a = (3) a = 3とされてしまうと、a[0]とアクセスができなくなってしまい、困ってしまうのでカッコは外れて欲しくない、という事象のこと。最終的には長さが0, 1のタプルは()および(1,)と表現するようになった。

Pythonの文字列は、表現以外はABCの文字列と非常に似た動作をするようにした。どちらも、文字列というのは変更不可能な文字列である。表現上異なっているのは、Pythonは最初の要素を0番目として順番を指定するところである。このときはインデックスで要素を指定できるデータ型にはリスト、タプル、文字列の3種類の型があった。私はこれらのシーケンスの操作を共通のコンセプトで一般化しようと決めた。この一般化により、どのシーケンス型であっても同じように基本の操作することができるようになった。例えば、長さの取得(len(s)), インデックス(s[i]), スライス(s[i:j]), ループ(for i in s)などである。

数値は、ABCから大きく外れた設計を行ったもののひとつである。ABCでは実行時には2つのデータ型があった。任意の精度の有利数として正確な数値が格納できる型と、CPU上の浮動小数点数で表された近似された値と拡張された指数の組み合わせで表現された数値型の2つである。有理数は私の視界の外にあった。私の体験談になるが、ABCで自分の税金を計算しようとしたことがあった。このプログラムはとてもシンプルに見えたが、ちょっとしたシンプルな数値を計算するのにものすごい時間がかかったのである。調査の結果、ABCは数千桁の精度の数値を使って計算を行い、画面に出力するときにギルダーとセントに丸めて表示しているということが分かった。Pythonでは伝統的な、CPUの持っている数値型と浮動小数点数をそのまま使用するという、良く使用されるモデルを採用した。Pythonの中では、これらの型はそれぞれ、C言語のデータ型のlongとdoubleに単純にマッピングされている。

訳注:ギルダーはGuidoの出身のオランダの通貨。セントは米ドルと同じく、100セント=1ギルダー。

正確で限界のない数値を使って計算を行うという使い方も重要であると感じたので、bignumデータ型を追加した。私はこれをlongと呼んでいた。私は既に数年にわたってABCのbignumを改良したいと思い続けていた。ABCのオリジナルの実装は私が最初にABCに貢献したもののひとつである。これは内部は10進数で表現されていた。このコードをPythonの中で使用するのは簡単であった。

Pythonにbignumを追加したが、重要なことは、すべての数値の計算にこれを使用したいと思っているわけではなかった点である。私が自分で書いたPythonプログラムと、CWIの同僚が書いたプログラムをプロファイルした結果、ほとんどのプログラムの実行時間のうち、数値の計算が全体に占める割合が大きいことが分かった。また、もっとも多く数値が使われる場面というのは、メモリの範囲内に収まるような小さい配列のインデックスである。そのため、私が想定したのは「厳密な数学」の計算を行うか、アメリカの国家予算をセント単位で計算するかというケース以外の、一般的に使われる場面のほとんどすべてはCPUの数値に納まる、というモデルである。

数値にまつわる問題

数値の実装、特に整数に関しては、設計当時に、私がいくつもの大きな設計間違いをしてしまった領域のひとつである。しかし、Pythonの設計に関連する重要な教訓をいくつも学ぶことができた。

訳注:ここでこれから述べる問題は現在では解決済みです。

Pythonが異なる二つの整数型を持っているので、プログラムの中でまずはこの二つを見分ける方法を考える必要があった。私が選択した解決策は、制限のない長い数値(long型)を扱いたい場合には、ユーザにきちんと宣言をしてもらう、というものであった。具体的には数値の後ろにLをつけて書く(例えば、1234L)という方法をとった。「ユーザには、興味のない実装の詳細を気にさせてはならない」というABCに影響された哲学があるが、この分野ではPythonはこれを破ることになってしまった。

残念ながら、これは数多くある数値の問題の中では、小さい問題のひとつでしかない。もっとひどい問題は、私が実装したint型とlong型では、いくつかのケースで微妙に異なる動作をしたことである。int型はコンピュータの数値型で表現されているため、計算結果がオーバーフローすると32bitの境界でクリップされてしまうのである。C言語のlong型でも、同じことは時々起こった。さらに、int型は通常は正も負も扱える(符号つき)ものとして処理されるが、ビット演算やビットのシフト操作、、8進数や16進数との間の相互変換時には、正だけの(符号なし)の整数として扱われた。long型は常に符号つきとして扱われた。そのため、いくつかの演算では、数値がint型かlong型かによって計算結果が変化してしまっていた。例えば、32ビット環境の場合、1<<31(1を左に31ビット分シフトする)の結果は、32ビットの数値の中で最大の負の値が返ってくる。そして、1<<32では0となる。しかし、1L<31(long型で表現された1を左に31ビット分シフトする)の結果は、2**31と同じ大きな数値になるのである。1L<<32は同様に2**32と同じ結果となった。

これらの問題のいくつかを解決するために、簡単な修正をほどこした。ユーザに内緒で数値をクリップしてしまう代わりに、ほとんどの数値演算子を書き換えて、結果が合わないときはOverflowError例外が上がるようにした。一部、ビット演算に関しては、ユーザはC言語とおなじ結果を期待すると思われたので、上記のチェックは入れなかった。もしこのチェックを入れていなければ、Pythonユーザは、C言語ユーザと同様に、符号つきの2**32という領域内でしかきちんと計算できないという認識に頼ったコードを書き始めていたことは疑いないだろう。そして、これらの問題の修正は、コミュニティにとってはより苦痛の大きい移行となっただろう。

オーバーフローのチェックは実装の詳細としては小さな問題に見えるかもしれないが、かなり困難を極めたデバッグの体験から、この機能はとても便利な機能であると実感していた。私が最初に実装したPythonプログラムのひとつに、Meertens数の計算という、シンプルな数値計算アルゴリズムを実装しようとしたものがあった。ABCのメインの作者のRichard Bird氏がCWIに勤めて25周年になった記念の、ちょっとした息抜きの数学の問題であった。最初のいくつかのMeertens数は小さいが、中間の結果は32ビットで扱えるよりも遥かに大きい数になるということを私は認識していなかった。私はこの事実を発見するまでは、長く苦しいデバッグの苦労を味わうことになった。この事実に気づいたときに、その場ですぐにすべての数値演算にオーバーフローチェックを入れて、C言語のlongで扱えない結果になるときはいつでも例外が上がるようにして、問題を特定することができた。オーバーフローのチェックにかかるオーバーヘッドのコストは、結果のための新しいオブジェクトの割り当てを実現するために既にかかっているコストを考慮すると、小さなものである。

訳注:どう書く?orgの説明によると、Meertens数の定義は以下の通りである。

正の整数 n を引数としてとり, 2^d1 * 3^d2 * 5^d3 ... * pk^dk を返す関数 がgoedel関数である。ただし,n を10進表現で k 桁の数としたときの各桁の数が数列 [d1,d2,d3,...,dk] をなすとし,dk が 1 の位,d1 が 10^(k-1) の位。また,pk は k番目の素数。

  • goedel 9 ⇒ 2^9 ⇒ 512
  • goedel 81 ⇒ 2^8 * 3^1 ⇒ 768
  • goedel 230 ⇒ 2^2 * 3^3 * 5^0 ⇒ 108

このgoedel関数を適用すると自分自身になるような数,すなわち goedel (n) == n となるような正整数 n がMeertens数である。

読者の方には、オーバーフローの例外を上げるというのも、最終的な解ではなかった、ということを謝らなければならない。当時の私は「T型の数値演算の結果は、同じT型になる」というC言語のルールにとらわれていたのである。このルールもまた、数値の意味を考える上で、私が大きな間違いをしてしまった原因である。数値の割り算の結果の切り捨てについてはまた別のブログの記事で説明をしたいと思う。後になって思うと、オーバーフローの時には例外を投げるのではなく、結果をlong型にして返すようにするべきであった。これは現在のPythonの実装のやり方である。しかし、このように移行するまでには長い期間がかかってしまった。

このような数に関する問題には苦労してきたが、ひとつだけ、とてもポジティブな考えをこの経験から生み出すことができた。それはPythonでは未定義な結果というのを根絶しよう、と意志を固めたことである。正しい計算結果が返せないときには、いつでも例外を上げるべきである。そのため、Pythonのプログラムは、見えないところで渡される未定義の値によって問題が引き起こされるということはないだろう。この考え方は、言語、つまり言語そのものと標準ライブラリの双方にとって、今日でも重要な原則となっている。

2009年4月26日日曜日

1996年にMicrosoftが出荷したPythonコード

原文:http://python-history.blogspot.com/2009/01/microsoft-ships-python-code-in-1996.html
原文投稿者:Greg Stein

私のPythonの歴史をここで共有することを受け入れてくれたGuido氏に感謝します。

自分のPythonとの出会いに関しては他の投稿に譲ろうと思うが、自分の仕事とPythonが関係することになったところから話を始めようと思う。私は数人のメンバーと一緒に、1991年にベンチャー企業を共同出資で設立した。私たちの業務は企業と消費者との間で行われる電子商取引を扱う大きなクライアント/サーバシステムであった。カスタムのTCPプロトコルを、古いX.25ネットワーク上で流したりしていた。私の出身はそのようなところである。

1995年には、我々が以前に行っていた予測とは大きく状況が変化し、多くの消費者がインターネット上に出てくるようになった。我々は、顧客(ベンダー)がインターネット上の消費者をターゲットとして使用できるシステムを準備する必要が出てきたのである。私は、どのようなアプローチをすればいいのかを調査するために、プロトタイピングツールとしてPythonを選択した。

最初の問題は、完全にブラウザベースのソリューションへの移行が必要となったことである。我々がそれまで開発してきたカスタムのクライアントソフトウェアはこれ以上生き残る術はなかった。我々は新しいショッピングの体験を消費者に提供する必要があり、サーバインフラはそれを支える必要があった。その当時はウェブブラウザとの通信というと、ApacheかNetscapeのHTTPサーバ上にCGIスクリプトを作成することを意味していた。CGIを使用すると、既存のバックエンドサーバに接続することができ、注文の処理、買い物かごの維持、商品情報の取得を行うことができた。これらのCGIスクリプトは素のHTMLを生成した。1995年にはAJAXはなかった。

このアプローチでは、リクエストごとに新しいCGIプロセスを起動するのに時間がかかるため、理想的な方法とは言えなかった。反応速度が極めて低かったのである。ちょうどそのころ、1995年の12月にワシントンDCで行われていたPythonワークショップに参加した。そのときに、Zopeでよく知られるDigital Creations社の人に、サーバプロセスの中に永続的にプロセスが走り続けるようになるというApacheとNetscapeのモジュールを紹介された。これらのモジュールはRPCシステムコール上のILU(多言語対応インタフェースシステム)を使い、バックエンドの長時間起動しているプロセスと通信を行うのである。このシステムを使用すると、CGIをフォークするオーバーヘッドがなくなり、ショッピングの体験が極めて快適なものに変わるのである。私はプロトタイプを実際のコードに変換していった。プロジェクトに取り組めば取り組むほど、どんどん良くなっていき、多くの人がこのプロジェクトに飛びついてくるようになった。Pythonのおかげで数ヶ月間、作業はとても早く進んだ。

1996年の1月に、Microsoft社が我々の会社を訪ねてきた。社内で電子商取引システムを構築しようと努力はしたものの、うまく道が見えないでいた。そのため、電子商取引に通じていて、機転の利く技術者を必要としていたのである。我々はこの分野では何年もの実績があった。春の間、交渉の間もソフトウェアの開発は続けた。そして、1996年の6月に買収は完了した。

Microsoft社にPythonコードの山と一緒に到着すると、まず行う必要があったことは、Windows NT上に電子商取引のソフトウェアを搭載する方法を理解することであった。Windowsの経験が豊富なチームに合流し、名前付きパイプを使ってバックエンドのサーバと通信するIISプラグインを構築した。このバックエンドサーバは、我々のPythonサーバコードが組み込まれたNTのサービスである。泥のようなスプリントが7月から始まり、我々はMicrosoft Merchant Server 1.0を1996年の10月に出荷することができた。

そう。もしシステムの中を見ることができたら、そこに隠れているのは・・・Pythonインタプリタと、いくつかの拡張DLL、そして.pycファイルの山である。Microsoft社はこの事実を宣伝することはなかったが、もし知っていたら見ることが可能だったのである。

Guido自伝 - 第二部, CNRI以降

原文:http://python-history.blogspot.com/2009/01/personal-history-part-2-cnri-and-beyond.html
原文投稿者:Guido van Rossum

前回投稿したときに触れたPythonワークショップの後に、CNRI(the Corporation for National Research Initiatives)のモバイルエージェントに関する仕事をしないか、というオファーが来た。CNRIはヴァージニア州のレストンにある非営利の研究ラボである。私は1995年4月にそこに参加した。CNRIのディレクターのBob Kahn氏は初めて、PythonとLispの共通点がどれぐらいあるか、という点について私に指摘をした。もちろん、PythonとLISPは外見の文法上はまったく異なるが。CNRIにおけるPythonの仕事は、DARPAが資金を提供するモバイルエージェントの研究からの間接的な資金援助を受けることとなった。DARPAはPythonを使用したプロジェクトをいくつもサポートしてくれたが、Pythonそのものの開発に対する直接のサポートはそれほどなかった。

CNRIでは、私はピュアPythonで書かれたモバイルエージェントシステムの構築を行う小さな開発者のチームの責任者をまかされ、メンバー集めも行った。最初のチームメンバーであるRoger Masse氏とBarry Warsaw氏はNISTでのPythonワークショップでPythonのバグに文句を言っていたメンバーである。それに加え、PythonコミュニティのメンバーであるKen Manheimer氏、Fred Drake氏も雇い入れた。MITの卒業生で、もともとテキスト検索の業務のために雇用されていたJeremy Hylton氏もチームに加わった。発足時はTed Strollo氏がチームを率いた。後にAl Vezza氏に変わった。

このチームは、私が追加のPythonコミュニティのインフラを作ったり、維持したりするのを助けてくれた。おかげでpython.orgのウェブサイトやCVSサーバ、そしてさまざまなPythonのSIG(特定のテーマを扱うグループ)などを作ることができた。Pythonのバージョン1.3から1.6まではCNRIからリリースされた。Python 1.5.2というバージョンは長い間、もっとも人気があり安定したバージョンであった。

GNU mailmanもここで誕生した。私は当初、Perlで書かれたMajordomoと呼ばれるツールを使用していたが、Ken ManheimerがMajordomoのメンテナンスができないということに気づいてPythonを使った解決策を探した。彼はJohn Viega氏が書いたシステムを見つけてメンテナンスを引き継いだ。Ken氏がCNRIを離れDigital Creationsに移った後は、Barry Warsaw氏が引き継いだ。最終的にはフリーソフトウェア財団がこれを評価してくれて、公式のメーリングリストツールとして採用されることになった。そのため、Barry氏はこれのライセンスをGPL(GNUパブリックライセンス)にした。

Pythonワークショップは最初は年に2回というペースで続いていたが、規模が拡大したり、移動が大変であるという理由から、すぐに年に一度のイベントになった。最初はイベントを開催したいと思った組織が運営を行ってきた。例えばNIST(初回), USGS(2回目、3回目)、LLNL(年に一度になった4回目)などの組織が運営を行った。最終的にはCNRIが組織を引き継ぎ、後には(WWW&IETFカンファレンスとともに)商業的にイベントを行うFortecとしてスピンオフすることになった。参加者はすぐに数100人にふくれあがった。私がCNRIを去ってFortecがイベントに関与しなくなった後は、オライリー主催のオープンソースカンファレンス(OSCON)と同時開催という形で、国際Pythonカンファレンスが開催された。しかし、同時に、Pythonソフトウェア財団(後で説明する)はPyConという新しい草の根のカンファレンスを開始した。

私たちは最初のPythonの(ゆるい)組織をCNRIの中に作った。Mike McLay氏とPaul Everitt氏は「Python財団」を作ろうと努力したが、計画は流砂に飲み込まれるかのように中断してしまった。Bob Kahn氏は「Pythonソフトウェアアクティビティ」を作ろうと持ちかけてきたが、これは法律上の独立性には問題があったが、CNRIの法律の傘下での(非営利の)活動をシンプルにしたようなものだった。PythonソフトウェアアクティビティはPythonユーザがコミットする大きなグループを集めるのには成功したが、独立性が欠けていたために、活動が制限されてしまっていた。

CNRIはJPythonの開発の資金面でのサポートのために、DARPAの協力を得た。JPythonは後にJythonと名前が縮められた。JPythonはJavaで書かれたJavaのためのPython実装であり、当初はMITの卒業制作の一環として、Jim Hugunin氏が開発していた。彼はこの仕事を完成させるために雇って欲しいというのをCNRIを納得させた。私の休暇中のできごとなので、もしかしたら逆にCNRIがJim氏に対して参加するように説得したのかもしれないし、明確なことは分からない。2年後にJim氏がXeroxのPARCで行われているAspectJプロジェクトに参加するためにCNRIを離れると、Barry Warsaw氏がJPythonの開発を引き継いだ。これからしばらく後の話になるが、Jim氏はPythonをMicrosoftの.NETに移植したIronPythonの実装も行った。また数値計算モジュールのNumeric Pythonの最初のバージョンも作成した。

Pythonを使用する他のプロジェクトも、CNRIでいくつか開始された。このプロジェクトの参加者の中から何人かの新しいPythonのコア開発者が現れた。特に、MEMS Exchangeプロジェクトで働いていたAndrew Kuchling, Neil Schemenauer, Greg Wardの3名である。Andrew氏はCNRIに参加する前からPythonに貢献をしていた。彼が最初に行った大きなプロジェクトはサードパーティのライブラリのPythonの暗号化ツールキットである。これは数多くの基本的な暗号化アルゴリズムをPythonユーザに提供するものである。

Pythonの成功の原動力となったのは、CNRIが、DARPAのような研究の補助金のような形ではなく、Pythonの開発を支援するというモデルを作ろうとしたことである。私たちはXコンソーシアムにならい、Pythonコンソーシアムを作り、最低参加費用として20,000ドルという金額を設定した。しかし、ヒューレットパッカード社の1法人以外の協力を得ることができず、コンソーシアムの構想は頓挫してしまった。次の開発基金の供給元として候補にあがったのが、DARPAの援助を受けていたプログラミング教育プロジェクトであるCP4E(Computer Programming For Everybody)だった。しかし、この基金もチームのすべてをまかなうには不十分であった。何年もの期間にわたって費用負担をまかなえる年配者(卒業生?)のネットワークがあるということがわかった。それは私が援助を受けられるものではなかったため、私は他の選択肢を探し始めた。

ドットコムバブルがはじけた(まだ完全にはじけたわけではなかったが)2000年ごろ、私とCNRIのPythonチームのうちの3人(Barry Warsaw氏, Jeremy Hylton氏, Fred Drake氏)はBeOpen.com社に移籍することを了承した。この組織はオープンソース開発者を雇用していたカリフォルニアのベンチャー企業であった。PythonコミュニティのキーメンバーのTim Peters氏も私たちに合流した。

BeOpen.comへの移籍にともなって予想されたことは、Pythonの将来の所有権をどうするのかが難しくなったということである。CNRIはライセンスを変更し、私たちに新しいライセンスの元でPython 1.6をリリースするように要求してきた。私がCWIにいた頃に使用してきたライセンスは、MITライセンスであった。CNRIでリリースされた時に使用したライセンスは、このライセンスに「CNRIは責任を放棄する」という一文を追加しただけの、基本的に同じライセンスであった。しかし、1.6のライセンスはCNRIの弁護士が「弁護士語」で作成した長ったらしいものになってしまった。

我々はフリーソフトウェア財団のRichard Stallman氏とEben Moglen氏とともに、この新しいライセンスについて何度も長い議論を行った。彼らは、そのライセンスがGPLと互換性がなく、すでにFSFには欠かせないツールになっていたmailmanが使用できなくなってしまうことに危機感を覚えた。Eric Raymond氏の協力も得て、CNRIのPythonのライセンスはFSF, CNRIの双方を満足させられるものに変更された。結果としてできたものは理解するのが難しくなってしまったが、私の口から良くなったと唯一言えることは、オープンソース・イニシアティブから正当なオープンソースライセンスであるというお墨付きをもらえたことである。その後は問題なく所有権の変更が2度行われた。最初はBeOpen.comで、その後はPythonソフトウェア財団である。しかし、実際にはCNRIの弁護士の立ち会いの下で行われた。

このような立ち上げの苦労も数多くあり、BeOpen.comのビジネス計画は派手に失敗してしまった。多くの負債を抱え、いくつかの役員の疑わしい行動もあり、私のチーム以外の何人もの開発者を失望させることとなった。

私のチームは幸運なことに、PythonLabsとして名前が知れ渡っていたために、強い引き合いがあった。Pythonをビジネスとして最初に使用した会社の一つであるDigital Creations社にチームごと雇われることとなった。Ken Manheimer氏は私たちよりも何年も前からここで働いていた。Digital Creations社はすぐに、自社の主なオープンソース製品のZopeにあわせて、Zope Corporationと名前を変更した。Zopeはウェブのコンテンツ管理システムである。Zopeの創始者のPaul Everitt氏とRob Page氏はNISTで行った最初のPythonワークショップの参加者であり、Jim Fulton氏がCTOをしていた。

Digital Creations社以外には、VA Linux社とActiveState社からもオファーを受けいていて、選択次第ではPythonの歴史は大きく違ったものになっていただろう。VA Linux社は株式市場の新星であったが、一時的にEric Raymond氏を書類上だけ大金持ちにした後は、最終的には株価は劇的に下がることとなった。振り返ってみると、創始者のDick Hardt氏が議論好きということを抜きにすれば、ActiveState社も悪い選択肢ではなかったかもしれないと思う。会社の場所がカナダでなければ、という前提の上であるが。

2001年に非営利組織のPythonソフトウェア財団を創設した。初期の構成メンバーは、その時点でPythonに貢献していた主な開発者たちである。Eric Raymond氏はその組織の出資者の一人である。この時期のことに関しては、また別の機会に書かなければならないと思っている。

Guido自伝 - 第一部, CWI

原文:http://python-history.blogspot.com/2009/01/personal-history-part-1-cwi.html
原文投稿者:Guido van Rossum

Pythonの初期の開発は、CWIと呼ばれる、オランダのアムステルダムにある研究施設で始まった。CWIはオランダ語の単語の頭文字を集めたもので、訳すとすれば、「数学&コンピュータ科学センター」ということになる。CWIはオランダの教育省と、他の研究の助成金によって運営されていて、アカデミックなレベルでコンピュータサイエンスと数学を研究する、とても面白い場所である。研究をしている多くの博士課程の学生と、「数学センター」というオリジナルの名前をいまだに覚えているOBの職業の専門家がいつでもそこに在籍している。当時の組織名はAlgol 68の開発で良く知られていた思う。

私は大学を卒業した1982年の後半からCWIで働き始めた。Lambert Meertens氏Steven Pemberton氏が率いていた、ABCグループにプログラマとして入った。4~5年後にめざましい成功を収めることなくABCプロジェクトが中断されてしまった後は、Sape Mullender氏が率いていたCWIのAmoebaグループに異動となった。Amoebaというのは、マイクロカーネルベースの分散システムで、大学教授のAndrew Tanenbaum氏がリーダーとなって、CWIとアムステルダム自由大学が共同で開発を行っていたプロジェクトである。1991年、Sape氏がトゥエンテ大学の教授になるためにCWIを離れると、Dick Bulterman氏が率いる、新しくできたCWIマルチメディアグループに最終的に落ち着いた。

PythonはCWIにおける私のすべての経験から生み出されたものである。今振り返ってみると、ABCのプロジェクトはPythonのキーとなるインスピレーションを、Amoebaプロジェクトでは開発に直結する大切なモチベーションを与えてくれた。マルチメディアグループではそれらをさらに成長させてくれた。しかし、私の知る限り、CWIではPythonの開発に対して公式に予算が計上されることはなかった。しかし、Pythonは、Amoebaとマルチメディアグループの両方の中で重要なツールとして使用され、発展していった。

私がPythonを作成する最初のモチベーションとなったのは、Amoebaプロジェクトの中で高次元の言語が必要とされているという認識からであった。システム管理ユーティリティの開発をC言語で行うと、時間がとてもかかることを実感していた。それに加えて、これらをBourneシェルでこれらの開発を行うとしたが、様々な理由からうまくいかなかった。もっとも重大な理由の一つは、Amoebaが根本から新しい概念の分散マイクロカーネルシステムであったため、Amoebaのプリミティブなオペレーションは、Bourne shell上で行える伝統的なプリミティブなオペレーションと大きく異なっている(Amoebaの方が粒度が細かい)。そのため、「C言語とシェルスクリプトの間のギャップを橋渡しをする」ことができる言語のニーズがあったのである。これはしばらくの間、Pythonを紹介するときによく使われるキャッチフレーズとなった。

この点に関して、「なぜ既存の言語を移植しなかったのか?」と疑問をもたれる思う。しかし、私の視点からは、この目標に合致する言語は、当時はそれほど多くはなかったように見えた。私はPerl3には慣れ親しんでいたが、Bourneシェル以上にUNIXの環境と結びついていた。また、私がPerlの文法を好きになれなかったのも理由のひとつである。プログラミング言語の文法に関して、私に強く影響を与えた言語はAlgol60, Pascal, Algol68などの言語である。これらの言語はすべて、私がその時に学んできたものである。そして、私の人生の4年間という期間を費やしてきたABCの影響も無視はできない。そのため、これはいいと私が思ったABCの要素はすべて取り込んだオリジナルの言語を設計したいと思っていた。同時に、私が気づいたABCの欠点もすべて修正したいと思った。

私が最初に修正しようとした問題は、プログラミング言語の名前であった。実際の所、ABCチームは言語の名前選びで苦労をした。当初ついていた言語名は"B"であったが、もっと古くて有名な他の同名のプログラミング言語のBがあり、まぎらわしかったために使えなくなってしまったのである。また、別の理由として、Bという名前が作業中の名前である、という意味あいもあった。これは、Bというのは言語名を入れる変数の名前であるというジョークであった(そのため、この記事の中ではイタリックにしてある)。ABCチームは、新しい名前を命名する公開コンテストを実施した。しかし、合格ラインを超えた応募はなく、結局予備のためにチーム内で用意していた候補から選ばれることとなった。プログラミングを「ABCと同じぐらい簡単にする」という意味を込めた名前であったが、私から見ても、多くの点で有名無実であると思ったものである。

そのようなことがあったため、命名に関しては、考えすぎた名前をつけるよりも、あまり考えないで行った方が良さそうだと考えた。私は最初に心に思い浮かんだものから名前を取った。それは私が好きなコメディグループ「空飛ぶモンティ・パイソン」からの発想だった。そもそもPythonの開発は正規のプロジェクトではなくて、こっそりと行われる"スカンクワークスプロジェクト"であったため、コメディから名前を取るぐらいの悪ふざけさ加減がちょうどいいと思ったのである。"Python"という言葉は覚えやすく、多少粋な感じであったし、プログラミング言語の名前は人物から付けるという伝統(Pascal, Ada, Eiffel)にも合っている。モンティ・パイソンチームは科学技術の分野の進歩に貢献したという名声を得てはいないと思うが、ギークが喜んでくれるものを提供できたと思う。CWIのAmoebaグループもTV番組の名前にちなんだプログラム名をつける伝統があったので、Pythonという名前はこれともフィットしている。

このように決めた名前であったので、私は何年もの間、Pythonという名前と蛇とを結びつけようという活動には抵抗をしてきた。しかし、オライリーが最初のPythonの書籍「Pythonプログラミング」の表紙に蛇のイラストを描こうとしたときに、この抵抗をあきらめることにした。動物の絵を使用するのがオライリーの伝統であったが、もし動物でなければならないのであれば、蛇であってもいいのではないかと思ったのである。

名前の問題が決着し、私がPythonの開発業務を開始したのは1989年の12月の末頃であった。1990年の最初の月には動作可能なバージョンができあがった。この作業のメモは残していないが、"pgen"と呼んでいたシンプルなLL(1)パーサジェネレータの実装からPythonを書き始めたのを鮮明に覚えている。このパーサジェネレータは現在でもPythonのソースコード実装の一部として含まれているし、すべてのコードの中ではあまり変更されていない部分であると思う。1990年にはCWIの何人かのメンバーが初期バージョンのPythonを使用し始めた。Amoebaグループ以外の人も使用した。同僚でもあるプログラマーのSjoerd Mullender氏(Sape氏の弟である)と、私がCWIを離れた後も何年もMacintoshへの移植のリードプログラマーを引き受けてくれることになるJack Jansen氏の2名が、私と一緒に開発に携わった主要な開発者である。

1991年2月20日に、私はalt.sourcesニュースグループ上で、世界に向けてPythonを初めて公開した。21分割されたuuencodeされたファイルを結合し、uudecodeをするとtarファイルが作成できるというものであった。この時のバージョンは0.9.0と付けられ、X11プロジェクトが使用していた、MITライセンスの亜種のライセンスの元に公開された。法的に責任を持てる団体として、CWIの親会社である"Stichting Mathematisch Centrum"の名前で公開された。それまで私が作成してきたプログラム同様、PythonもまたEric Raymond氏Bruce Perens氏が1997年の終わり頃にオープンソースという用語を作り出す以前から、オープンソースであった。

公開するとすぐに多くのフィードバックがあった。これに励まされるようにして、これから何年もの間に一定のペースで次々とリリースを行った。ソースコードの変更を記録するのと、Sjoerd氏、Jack氏とコードの責任を共有するためにCVSを使用し始めた。偶然にも、Pythonと同様にCVSも、ABCグループの初期メンバーであるDick Grune氏によってシェルスクリプト集として開発されていた。当時はWebはまだなかったが、私はFAQを書き、当時のFAQの慣習に従っていくつかのニュースグループに定期的にポストしていた。メーリングリストも開始した。1993年の3月にはうれしいことに、私が直接関与しないかたちでcomp.lang.pythonニュースグループが作成された。ニュースグループとメーリングリストは、現在でも稼働している双方向のゲートウェイを通じて統合された。当時大きなシェアを持っていたオープンソースのメーリングリスト管理システムのmailmanにはこのような機能はなかったため、このゲートウェイはPythonで作成された。

1994年の夏に、ニュースグループ上で「もしGuido氏がバスに轢かれたら?」というタイトルのスレッドがニュースグループをにぎわした。これは私個人の貢献に、Pythonのコミュニティの成長が依存していたというのが発端である。この結果として、Michael McLay氏から招待を受けて、2ヶ月間、客員研究者としてNIST(アメリカ国立標準技術研究所)に行くことになった。NIST(wikipedia)はメリーランド州のゲーサーズバーグにあり、以前は国立標準局と呼ばれていた。Michael氏はNIST内に、多くのPythonに興味を持つ「顧客」を持っていた。彼らは標準化に関するさまざまなプロジェクトにPythonを使用したいと考えていた。Micheal氏は私が彼らのPythonのスキルアップの手助けに必要であるという目的で、私の滞在費の予算を確保してくれた。可能であれば彼らのニーズに従ってPythonを改善するというのもその目的に含まれていた。

1994の11月、私がNISTの滞在中に、NISTのプログラマのKen Manheimer氏の多大な援助と励ましによって、最初のPythonワークショップが開催された。およそ20名の参加者がいたが、そのうちの半数は現在もPythonのコミュニティ活動にアクティブに参加している。何人かのメンバーはオープンソースプロジェクトのリーダーになっている(ZopeJim Fulton氏と、GNU mailmanBarry Warsaw氏)。NISTのサポートにより、サンタフェで開催されたUsenix Little Languagesカンファレンスで、400人もの人の前でキーノートを発表することもできた。このカンファレンスを主催したTom Christiansen氏は、気さくなPerl支持者であり、Perl作者のLarry Wall氏とTcl/Tk作者のJohn Ousterhout氏を紹介してくれた。

2009年4月24日金曜日

Pythonの沿革

原文: http://python-history.blogspot.com/2009/01/brief-timeline-of-python.html
原文投稿者: Guido van Rossum

Pythonの開発がスタートしたのは、Tcl, Perl, Ruby(これはPythonよりも遅い誕生であるが)など、多くの他の動的(で、オープンソース)なプログラミング言語が活発に開発され、人気を獲得しつつある時期であった。Pythonを適切な歴史観で語る一助になると思うので、Pythonのリリースの歴史を以下のリストにまとめた。すべてのイベントをきちんと記録してきたわけではないので、初期の日時は多少あいまいな部分もある。

リリース日時バージョン
1989年12月実装開始
1990年CWI(オランダの国立情報工学・数学研究所)
内での内部リリース
1991年2月20日0.9.0(ニュースグループのalt.sourcesでリリース)
1991年2月0.9.1
1991年秋0.9.2
1991年12月24日0.9.4
1992年1月2日0.9.5(Macintoshのみ)
1992年4月6日0.9.6
1992年(時期不明)0.9.7beta
1993年1月9日0.9.8
1993年7月29日0.9.9
1994年1月26日1.0.0
1994年2月15日1.0.2
1994年5月4日1.0.3
1994年7月14日1.0.4
1994年10月11日1.1
1994年11月10日1.1.1
1995年4月13日1.2
1995年10月13日1.3
1995年10月25日1.4
1998年1月3日1.5
1998年10月31日1.5.1
1999年4月13日1.5.2
2000年9月5日1.6
2000年10月16日2.0
2001年4月17日2.1
2001年12月21日2.2
2003年7月29日2.3
2004年11月30日2.4
2006年9月16日2.5
2008年10月1日2.6
2008年12月3日3.0

現在でもpython.org上でPRされているリリースにはハイパーリンクを貼っておいた。ここでは書いていないが、多くのリリースに対して、2.0.1といったいくつかの小さいリリースも行われている。しかし、細かいリリースまで表に入れてしまうとリストが長くなりすぎてしまうため、省略してある。非常に古いソースのアーカイブファイルも、http://www.python.org/ftp/python/src/にて現在もアクセスすることができる。古いさまざまなバイナリのリリースや、それ 以外の歴史的なものも、このフォルダの上位階層で見つけることが可能である。

Pythonの設計哲学

原文: http://python-history.blogspot.com/2009/01/pythons-design-philosophy.html
原文投稿者: Guido van Rossum

今後のブログのエントリーは、生々しいPythonの歴史の詳細に入り込んでいく予定である。しかし、それに触れる前に、私がPythonの設計や実装をしている時に、意志決定を助けてくれた哲学的なガイドラインについて詳しく説明をしていきたいと思う。

まず最初に、Pythonはもともと"スカンク・ワークス(社内の秘密裏のプロジェクトの意味)"として計画がスタートした。公式な予算などなかったし、私は素早く結果を出そうとしていた。マネジメントにプロジェクトのサポートを説得する、というのがその理由の一つである(そして、その目論見は達成できた)。このような状況から、時間を節約するためのルールがいくつか導き出された。

  • 道理に叶うときはいつでも、他の場所からアイディアを借りてくる。
  • 「物事は可能な限り単純化されるべきである。ただし、それ以上単純にしてはいけない」(アインシュタイン)
  • 一つのことに集中する(UNIXの哲学)
  • パフォーマンスについては気にしないで。必要であれば、後から最適化を行うので。
  • 環境に戦いを挑むな。そして流れに身を任せよ。
  • 完璧を求めようとするな。「十分に良い」で足りることがほとんどである。
  • (それゆえに)たまに手を抜くのは問題はない。特に、後でやれば正しくできる場合には。

これ以外の原則は時間の節約を意図したものではなかった。たまに正反対なことを言っているものも含まれていた。

  • Pythonの実装は特定のプラットフォームに縛り付けるべきではない。いくつかの機能が動作しないのは問題ないが、コアはどこでも動作すべきである。
  • コンピュータが行えるような細かい仕事はユーザにさせてはならない。(私はいつもこの原則に従っていたわけではなく、後のセクションでこれの悲惨な影響についていくつか説明する)。
  • プラットフォームに依存しないユーザコードをサポートし、また、そうなるように奨励すべきである。ただし、プラットフォームの能力や特性を生かすためのアクセスを妨げてはならない。(これはJavaとは対照的である)。
  • 巨大で複雑なシステムは、さまざまな階層で拡張可能であるべきだ。きれいに拡張できる場合もあるだろうし、洗練したやり方ができないこともあるだろうが、これをすることで、ユーザが自分自身を助ける機会を最大限に増やすことができる。
  • エラーは致命的であってはならない。エラーの状況であっても、バーチャルマシンの機能が壊れていなければ、ユーザコードはエラーから復帰できるようにすべきである。
  • 同時に、エラーはこっそり握りつぶしてはならない。(実装時には、これらの2つの項目により、例外を使用するという意志決定が自然に行われた)
  • ユーザのPythonコードのバグにより、Pythonのインタプリタが未定義な動作を起こしてはならない。コアダンプは、決してユーザの責任ではない。

最終的に、私は良いプログラミング言語設計のためのさまざまなアイディアを身につけることができた。このアイディアの多くを学んだきっかけは、私が初めて実際の言語の実装と設計を体験をしたABC(訳注:教育用のプログラミング言語の名前)のグループに参加したことである。これらのほとんどのアイディアは、エレガンス、シンプルさ、読みやすさなど、主観的な概念を中心に展開されているため、形式知に表出化するのが困難であった。

後ほど、ABCがPythonに与えた影響について詳しく述べるが、まずは読みやすさのルールについて説明してみたい。まず、句読記号文字は、一般的な英語的な記述や、高校レベルの代数に沿った、伝統的な使い方をすべきである。ただし、かけ算の"x*y"、配列アクセスの"a[i]"、属性アクセスの"x.foo"など、プログラミング言語の中で長い間使用されてきた表記法がある場合は例外とすることもある。ただし、Pythonでは変数を明示するために"$"を使用したり、副作用のある操作を明示するために"!"を使用することはない。

Tim Petersは古くからのPythonユーザである。最終的にもっとも多くのコミットをする、頼りになるコア開発者となった。彼は、私が言語化してこなかった設計原理を記録しようとして、"Zen of Python"(リンク先は英語)と呼ばれるものを作成した。全文を引用する。

  • 醜さよりも美しさ
  • 不言実行よりも有言実行
  • 複雑よりもシンプル
  • 入り組んだ1行よりも、複数行のコード
  • 深い階層よりも平坦な階層
  • 過密なコードよりも疎なコード
  • 読みやすさに勝るものなし
  • 「特別な場合」というのは言い訳にならない
  • しかし、ルールに愚直であるよりは実用性
  • 問題があるときには、こっそりと処理してはならない
  • 隠すすることが明示されている場合を除いて
  • 解釈が多数ある場合、推測でやってはならない
  • 実現する方法は一つ、なるべく一つであるべきだ
  • オランダ人※にしか明確でないこともありえるが
  • 「実現してないいつか」 よりも「今」
  • あわてて今やるよりはしない方がいいことも多い
  • 説明が大変なら、それは悪いアイディアだ
  • 説明が簡単なら、それはいいアイディアだろう
  • 名前空間はすばらしいアイディアだ
    それよりもすごいことをやろう!

※訳注: おそらくPython作者のGuidoのこと

ABCにおける私の経験はPythonにとても大きな影響を与えたが、ABCグループの設計原理の中には、Pythonのものと根本的に異なるものがいくつか存在する。これらに関しては、Pythonは意図的に違う方向を目指している。

  • ABCグループは完璧性を求めて努力していた。例えば、ABCでは、大きいコレクションでの性能を改善するために、ツリーを元にしたデータ構造のアルゴリズムを使っていた。しかし、これは小さなコレクションについては良くなかった。
  • ABCグループでは、「大きくて、悪いものがたくさん存在するコンピュータの世界」からユーザをなるべく完璧に隔離しようとしていた。数値の格納できる範囲や、文字列の長さ、コレクションのサイズの限界(メモリの限界を除き)だけでなく、ファイルやディスクを扱って「保存する」といったことや、他のプログラムを扱う必要性からもユーザを遠ざけようとしていた。ABCは必要なモノがすべて手に入る唯一のツールであろうとした。このため、ABCグループではABCに特化した、完全に統合された編集環境を必要とするまでになった。結果的には、ABCの環境から逃げる方法もないことはなかったが、言語から直接アクセスすることはできなかった。
  • ABCグループでは、ユーザはコンピュータの経験はまったくない(もしくはそれを忘れようとしている)という想定をしていた。そのため、標準的なプログラミング用語よりも、「新しい人にとって親しみやすい」という別の用語が導入された。例えば、手続きは"手引き(how-tos)"、変数は"場所"とされました。
  • ABCグループでは、進化の道筋というのを考慮しないでABCを設計した。言語の設計の過程の中では、ユーザの参加というのは期待されていなかった。ABCはクローズなシステムとして、設計者ができるかぎり完璧なものが作成された。ユーザが「ボンネットの中を調べる」ようなことは推奨されていなかった。プロジェクトの後半には、実装されたプログラムの一部を先進的なユーザ公開しようという話も出てきたが、この話が実現することはなかった。

様々な意味で、Pythonをここまで成功させてきた主な理由の一つが、Pythonを開発するときに私が使用してきたこれらの設計哲学であったと思う。例え完璧を目指さなくても、アーリー・アダプターの人たちの目的を達成するのに、Pythonは「十分に良い」働きをしてきた。ユーザ基盤が成長してくるにつれて、ユーザから出される改善要望が徐々に言語に取り込まれてきた。後のセクションで解説していくが、多くの改良により多くの部分の変更や、言語のコア部分の作り直しが行われた。現在でも、Pythonは改良され続けている。

イントロダクションと概要

原文: http://python-history.blogspot.com/2009/01/introduction-and-overview.html
原文投稿者: Guido van Rossum

イントロダクション

Pythonは現在、もっとも人気のある動的言語のひとつである。この言語にはPerl, Tcl, PHP, そして新規参入のRubyなどがある。しかし、Pythonは本当はLispやSmalltalkのような汎用目的のプログラミング言語であるにもかかわらず(他の言語も同じであるが)、「スクリプト」言語として見られることが多い。今日、Pythonは使い捨てのスクリプト言語から、24時間365日間中断せずにサービスを提供する、巨大でスケーラブルなウェブサービスにまで幅広く使用されている。また、GUIやデータベースのプログラミングや、クライアントサイド、サーバーサイドのウェブプログラミング、そしてアプリケーションのテストにも使用されている。また、科学者が世界で一番早いスーパーコンピュータ向けのプログラムを書いたり、子供がプログラムを初めて学ぶ言語としても使用されている。

このブログでは、Pythonの歴史にスポットライトをあてようと思う。特に、どのようにPythonが開発されてきたかや、どのように設計に影響を与えてきたか、どのように間違って、どのように学んできたか、そしてこの言語は将来どのような方向に進んでいるのかを紹介したい。

謝辞:私は、このブログで多くの良い文章を書くのに、Dave Beazleyのお世話になっている。(また、このブログを始めるきっかけについてはさらにお世話になった。私の他のブログを見て欲しい)

Pythonの概要

Pythonを見た人の多くは、Pythonは表面的にはC言語やPascalといった、伝統的なプログラミング言語に似たコードが書けるため、Pythonコードの見た目に関して感銘を感じる人が多い。これは偶然の一致ではない。PythonはC言語から、文法の多くの要素をもらってきているからである。例えば、多くのPythonのキーワード(if, else, while, forなど)はC言語と同じであるし、Pythonの識別子(関数名など)のルールはC言語と同じであるし、ほとんどの標準の演算子はC言語と同じ意味を持っている。もちろん、PythonとCは完全に一致しているわけではない。一番大きな違いは、C言語が文のグループ化に中括弧を使用する代わりに、Pythonではインデントを使用している点である。たとえば、以下のようなC言語のコードがあったとする。

if (a < b) {
    max = b;
} else {
    max = a;
}

Pythonはただ中括弧をすっかりとりはらった(ついでにセミコロンも置き去りにしてきた)だけで、以下のような構造をしている。

if a < b:
    max = b
else:
    max = a

これ以外のPythonがC言語のような言語と大きく異なる領域としては、動的な型を使う部分もそうである。C言語では常に、変数を定義する際は、intやdoubleといった型情報を与えて、宣言を明示する必要がある。この情報は、プログラムのコンパイル時の静的なチェックで使用されるだけでなく、変数の値を格納する際のメモリの位置の割り当てでも使用される。Pythonでは、変数はオブジェクトを参照するための名前でしかない。変数は代入する前に宣言する必要はなく、プログラムの実行中に型を変えてしまってもかまわない。他の動的言語と同様に、すべての型のチェックは、事前に行われるコンパイル時に行われるのではなく、インタプリタにより実行される時に行われる。

Pythonではプリミティブな組み込みのデータ型にはブール型, 数値(コンピュータの数値表現, 任意精度の数値、実数の浮動小数点数, 複素数の浮動小数点数), 文字列(8ビット, ユニコード)がある。これらはすべてイミュータブル(変更不可能)な型である。これは作成された後には、オブジェクトで表現された値は変更できないということを意味している。組み込みの複合データ型にはタプル(変更不可能な配列)、リスト(サイズの変更が可能な配列)、辞書(ハッシュテーブル)がある。

プログラムを組み立てるための仕組みとして、Pythonはパッケージ(モジュールやパッケージをグループにしたもの), モジュール(ひとつのソースファイルの中で定義され、関係付けられたコード群), クラス、メソッド、関数をサポートしている。フロー制御としては if/else, while, 任意の"反復可能"なオブジェクトの中でループを行う高レベルなfor文をサポートしている。エラー処理の機能としては、Pythonは例外を使用する。Pythonの例外は中断後の再開はできない。raise文で例外を投げ、try/except/finally文を使用して例外の処理方法を定義する。組み込みの操作は、エラーの状況に遭遇すると例外を投げるようになっている。

Pythonでは、すべての名前の付けられるオブジェクトは「ファーストクラス」であると言える。ファーストクラスというのは、関数、クラス、メソッド、モジュール、その他のすべての名前の付けられるオブジェクトは、実行時に自由にパラメータとして渡したり、分析(inspect)したり、さまざまなデータ構造(リストや辞書など)に格納したりすることができる。オブジェクトについても説明すると、Pythonではユーザ定義クラス、継承、実行時のバインディングといったオブジェクト指向プログラミングをフルサポートしている。

Pythonは大規模な標準ライブラリを持っている。Pythonの人気がある主な理由のひとつである。標準ライブラリは100以上のモジュールで構成されており、今でも追加され続けている。これらのモジュールの中には、正規表現のマッチング、標準の算術関数、スレッド、OSのインタフェース、ネットワークプログラミング、インターネットの標準プロトコル(HTTP, FTP, SMTPなど)、Eメール、XML処理、HTMLのパース、そしてGUIツールキット(Tcl/Tk)などがある。

これに加え、サードパーティで作成されている、大量のモジュールやパッケージなどもある。これらの多くはオープンソースである。探してみると、リストにできないほど大量のウェブのフレームワーク、多くのGUIツールキット、高効率な算術ライブラリ(多くのポピュラーなFortranのパッケージのラッパーも含む)、データベースのインタフェース(Oracle, MySQLなど), SWIG(任意のC++ライブラリからPythonモジュールを作成するツール)などがある。

Python(さらにいえば、他の動的な言語も)の主要な魅力は、とても複雑に見えるタスクを、とても少ないコードで表現できるというところにある。以下のシンプルなPythonスクリプトは、ウェブページを取得し、URL参照を探してし、最初の10個を画面に出力するサンプルである。

# Webをスキャンして参照を探す

import re
import urllib

regex = re.compile(r'href="([^"]+)"')

def matcher(url, max=10):
    "最初のいくつかのURL参照を探し出して出力する"
    data = urllib.urlopen(url).read()
    hits = regex.findall(data)
    for hit in hits[:max]:
        print urllib.basejoin(url, hit)

matcher("http://python.org")

このプログラムを改造してウェブのクローラーを作成するのは簡単であるし、実際、Scott Hassanは私に、Googleの最初のウェブクローラーはPythonで書かれたんだ、と教えてくれたことがあった。今日、Googleでは、広告管理の自動化システムの構築から、社内の業務のさまざまな側面の管理まで、数百万行のPythonコードを使用している。(注意: 私は現在、Googleの従業員でもある。)

目に見えない裏側では、Pythonはバイトコンパイラとインタプリタを組み合わせるというオーソドックスな実装になっている。コンパイルはモジュールのロード時に暗黙的に行われる。また、いくつかの言語の下層部では、実行時にコンパイラが利用可能であることが必須となっている。PythonではC言語で書かれている実装がのデファクトスタンダードであるが、想像しうる限りすべてのハードウェアやソフトウェアのプラットフォーム上で使用することができる。最近では、C言語以外で実装されている処理系が人気になりつつある。JythonはJVM上で実行されるバージョンで、Javaとシームレスな統合が可能となっている。IronPythonはMicrosoftの.NETプラットフォームのためのバージョンであり、同様に.NET上で動作する他の言語と統合することができる。PyPyはPythonの最適化コンパイラ/インタプリタであり、Pythonで実装されている。PyPyはEUの基金の下で活動する研究プロジェクトである。また、C言語の他のバリエーションの実装として、Stackless Pythonもある。これは、関数やメソッドの呼び出しのC言語のスタックへの依存を減らした実装で、コルーチンや継続、マイクロスレッドをサポートしている。