2010年7月17日土曜日

import antigravity

原文:http://python-history.blogspot.com/2010/06/import-antigravity.html
原文投稿者:Guido van Rossum

Pythonについて説明をしているXKCDコミックを参照するというantigravityモジュールが、Skip MontanaroによってPython 3に追加された。私が知る限り最初にこのモジュールについて焦点をあてたブログはこれである: http://sciyoshi.com/blog/2008/dec/30/import-antigravity/

しかし、このモジュールの本当の起源はGoogle App Engineである。私たち(訳注: GuidoはGoogleで働いている)がApp Engineを公開した、2008年4月7日の直前だった。公開の数週間前の、ほとんどのコードがコードフリーズしたときに、GoogleのApp Engineチームは何かイースターエッグを忍び込ませたいと考えた。時には複雑で、時にはあいまいで、時にはリスキーな、何度にも渡るすばらしい議論の末に、"antigravity"モジュールが選択された。App Engine版はPython 3版よりも多少がんばった作りになっている。App Engine版では、fly()関数が定義されていて、次の2つのうちの一方の動作をランダムにランダムに行う。1つ目は10%の確率で発生するモノで、XKCDのコミックにリダイレクトでジャンプする。もう一方はHTML内に、テキスト版のコミックを単純に書き出すだけのものである(最後の行にコミックへのリンクが表示される)。次のようなmain()プログラムを作成すると、App Engineのアプリケーション内でこれを呼び出すことができる。

import antigravity

def main():
    antigravity.fly()

if __name__ == '__main__':
    main()

[更新情報] Python 3の標準ライブラリ版では、ソースコードの中を見てみると、イースターエッグの中にさらにイースターエッグが仕込まれている。XKCDのgeohashアルゴリズムについて説明している関数が定義されている。

2010年7月13日火曜日

import thisとThe Zen of Python(2)

原文:http://www.wefearchange.org/2010/06/import-this-and-zen-of-python.html
原文投稿者:Barry Warsaw

注:本エントリーは、Guidoのブログではなく、そこで紹介されていた、Barry Warsaw氏のブログの翻訳です。翻訳と公開の許可をしてくださったBarry Warsaw氏に感謝します

Richard Jones氏は現在(元記事執筆時点)、PyCon Australiaでする話の準備をしている。彼はその準備の中で、私に"Zen of Python"の歴史についてたずねてきた。それはTim PetersがPython界に永遠に残した言葉で、Pythonの本質的な真実を良く伝えるものであり、さまざまな場面で引用されている。最初に調べたときには、このリストが最初に公表された時の情報を探すことはできなかったが、その後、自分のメールのアーカイブをすみずみまで調べたところ、"Zen of Python"が最初にPython-listというメーリングリストに投稿された時のメールを見つけることができた。"The Python Way"というタイトルで、1999年の7月4日に投稿されたものであった。

すぐに最初の出典を見つけることができなかったので、自分のアーカイブの探査に戻ったり、"this"モジュールの解析を行っていた。最近のPythonのインタプリタでは、次のようにタイプすると、"Zen of Python"を読むことができるというのをご存知だろうか?(訳注:日本語訳はこちら)

% python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

"import this"の背景の話は楽しいものなので、私は、これが追加された経緯について紹介したら面白いだろうと考えた。おそらく、Guidoの"History of Python"というブログに何かストーリーを追加するような内容になるはずである。

2001年の秋に、ForetecInternational Python Conference #10 (IPC 10, PyConの先駆けとなるイベント)の開催準備をしていた。ForetecはCNRIの子会社のイベント運営会社で、Pythonlabsの設立のために退社する2000年まで、Guido, Fred,Jeremyと私を雇っていた。その会社は動きが悪いこともあったが、好意的な面も多数ある会社であった。その時には既に、私たちは友人たちと一緒にZope Corporation(おそらく当時はまだDigital Creationsという名前)で働いていたが、ForetecはIPCの開催を継続していた。ForetecはカンファレンスのスローガンをTシャツにプリントしたいと考えており、Pythonコミュニティからスローガンの提案を集めようと考えていた。提案されたエントリーを審査して、勝者を決めるというタスクを行うことをPythonlabsは同意した。しかし、私の記憶では、当時奥さんの出産を控えていたGuidoには、エントリーを審査する時間とエネルギーがなかった。

私たちは500ほどのエントリーを受けつけたが、ほとんどはひどいものであった。Timは「Louise、5分も見ていると、脳が溶け出しそうになるよ」というようなことを言っていたが、なんとか作業を継続して、130エントリーほどになるまでカットした。最後の勝者が決まる、最後の1分まで、私たちはただただ気が狂いそうだった。Timは私に、リストを交換する提案をしました。リストを半分にして、半分だけ交換しました。Timは私よりも遥かに数学が得意であり、Pythonの数値の割り算のくせを忘れていたため、最後の2つのエントリーが抜けてしまった。それらが「好きなものはすべて食べられます。咀嚼するのはオプションです」(私には良いところがまったくないと思われた;)と、「import this」であった。Timは「Pythonのプログラムに関して学ぼう」というエントリーについて二人ともが良いと思っていた土壇場になって、このおもしろいものを復活させた。

私はこの「import this」という偉そうなセンテンスを気に入った。また、このセンテンスを利用すればマイケル・ジャクソン風のすばらしいTシャツが作れそうだという可能性を感じた。

"import this"を選択してすぐに、それをプログラムとして実装した方がいい、ということに気づいた。Python 2.2のリリースが間近だったため、私は、コードのチェックインを知らせる機能をオフにして"this.py"というthe Zen of Pythonを表示させるモジュールを忍び込ませてはどうか?という提案をした。TimかGuidoのどちらかが、内容を難読化するのにrot13という暗号化をしてみたらどうか?と提案した。その仲間内以外の人には誰にも話しをしなかった。Googleを探索して調べたところ、IPC 10が終了してすぐに、私たちはPython 2.2.1としてthis.pyをコミットして、このイベントを祝していた。つまり、2.2.1には、本来リリースすべき真面目な機能に加えて、このジョークの機能が追加されていたのである。私の記憶が正しければ、ここで仕込んだ小さなイースターエッグが発見されるまでには、多少の時間を要した。

これは、Pythonコミュニティにユーモアがあった時代を思い出させてくれるできごとである。

import thisとThe Zen of Python

原文:http://python-history.blogspot.com/2010/06/import-this-and-zen-of-python.html
原文投稿者:Guido van Rossum

Barry Warsaw氏が、Pythonの歴史の中で、今まで明らかにされていなかった(記録に残したい)事実を紹介する面白いエントリーをブログに投稿している。

http://www.wefearchange.org/2010/06/import-this-and-zen-of-python.html

2010年7月8日木曜日

新スタイルクラスの内部の話

原文:http://python-history.blogspot.com/2010/06/inside-story-on-new-style-classes.html
原文投稿者:Guido van Rossum

[注意:この投稿はとても長くて技術的です]

表面上は、新スタイルクラスは、元々のクラスの実装と非常に似通って見えるが、新スタイルクラスでは次のような数々の新しいコンセプトが導入されている。

  • __new__()という名前の低レベルのコンストラクタ
  • 属性アクセスのカスタマイズを一般的にできるようにするデスクリプタ
  • 静的メソッドとクラスメソッド
  • プロパティ(演算してから結果を返す属性)
  • デコレータ(Python 2.4から導入)
  • スロット
  • 新しいメソッド解決順序(Method Resolution Order, MRO)

このエントリーでは、これらのコンセプトについて光を当てていこうと思う。

__new__()という名前の低レベルのコンストラクタ

クラスを定義するときには通常の場合には、インスタンスの生成後にどのように新しいインスタンスを初期化するのかを定義する、__init__()メソッドを実装していた。しかし、クラスの作者が、インスタンスの生成方法そのものもカスタマイズしたいというケースがいくつかある。例えば、オブジェクトを永続化されたデータベースから復元する場合などである。"new"モジュールなど、普通ではない方法で特定の種類のオブジェクトを作成するためのライブラリはいくつかあったが、旧スタイルクラスではオブジェクトの生成をフックしてカスタマイズする方法が提供されていなかった。

新スタイルクラスでは、__new__()という新しいクラスメソッドが提供されたことで、クラスの作者が新しいクラスのインスタンスを生成する方法もカスタマイズできるようになった。__new__()メソッドをオーバーライドして、以前作成したインスタンスを返すことで、クラス作者はシングルトンパターンのようなパターンも実装することが可能である。また、他のクラスのインスタンスも返すことができる。しかし、__new__()の活用法には、これ以外にももっと重要なものがある。例えば、pickleモジュールでは、__new__はシリアライズされたオブジェクトを復元してインスタンスを作成するのに使用されている。このケースでは、インスタンスは生成されるが、__init__()メソッドは呼び出されないという実装になっている。

他にも、変更不可(immutable)型のサブクラス化を行う際にも、__new__が役に立つ。変更不可能という特性上、標準的な__init__()メソッドでは、このようなオブジェクトを初期化することはできない。そのため、オブジェクトの作成時に何か特別な初期化処理を行う必要がある。もし、変更不可能なオブジェクトの中に格納される値を変更したい場合には、ベースクラスの__new__メソッドに変更後の値を渡すことによって、このような処理を行うのに利用できる。

デスクリプタ

デスクリプタは、旧スタイルクラスの実装の中心となっている、束縛メソッドの概念を一般化したものである。旧式のクラスでは、インスタンス属性がインスタンス辞書の中から見つけられない場合には、クラス辞書を引き続き探索し、その後はベースクラスのクラス辞書を再帰的にたどっていくという振る舞いをする。もし属性がクラス辞書の中で見つかると、インスタンス辞書とは異なり、インタプリタが見つかったオブジェクトがPythonの関数オブジェクトであるかどうかがチェックされる。もし、そのオブジェクトが関数オブジェクトだった場合には、見つけたオブジェクトを返値にするのではなく、カリー化関数のように振る舞うラッパーオブジェクトを返す。ラッパーが呼ばれると、インスタンスを引数リストの先頭に挿入してから、オリジナルの関数が呼び出される。

例えば、クラスCのインスタンスxがあると想定しよう。今、このインスタンスに対して、x.f(0)という呼び出しが行われたとする。この操作を分解すると、まず、"f"という名前の属性をインスタンスxから探しだし、引数として0を渡して呼び出される。もし、"f"がクラスの中で定義されたメソッドと一致するのであれば、次の擬似コードの関数のような振る舞いをするラッパー関数を属性として返す:

def bound_f(arg):
    return f(x, arg)

もしも引数の0とともにこのラッパーが呼ばれると、このラッパー関数はx0という二つの引数をともなって"f"を呼び出す。これが、クラスのメソッドが"self"引数を取得する基本的なメカニズムである。

(ラップされていない)関数オブジェクトfにアクセスする別の方法としては、クラスCの属性として"f"という名前の属性の問い合わせをするというものがある。このような検索を行うと、ラッパーのつかない、関数fを単純に返す。言い換えると、x.f(0)は、C.f(x, 0)と同じということである。Pythonの中では、これらの呼び出しは基本的に等価である。

旧式のクラスでは、属性を調べて、他の種類のオブジェクトが見つかった場合には、ラッパーは生成されずに、クラス辞書の中から見つかったオブジェクトがそのまま返される。これにより、クラス属性をインスタンス変数の"デフォルト"値として利用することもできる。例えば、上記の例であれば、もしクラスCが"a"という属性名で数値の1を持っていて、xのインスタンス辞書に"a"というキーがなければ、x.a1となる。x.aに割り当てると、xのインスタンス辞書に"a"というキーができ、属性辞書の探索順序の影響でクラス属性の値が隠蔽される。x.aを削除すると、隠されていた値(1)に再びアクセスできるようになる。

残念ながら、何人かのPython開発者により、この実装の限界が発見されてしまった。限界の一つ目が、いくつかのメソッドPythonで実装し、他のメソッドをCで実装するという"ハイブリッド"クラスを実装することができないというものである。これはPythonの関数だけが上記のような方法でインスタンスにアクセスするためのメソッドを提供していたのと、この振る舞いが言語にハードコードされていたのが原因である。また、C++やJavaプログラマーが親しんでいる、静的メンバー関数のような異なる種類のメソッドを定義する方法もなかった。

この問題に対処するために、Python 2.2からは、上記のラッピングの振る舞いを素直に一般化した仕組みが導入された。Pythonの関数オブジェクトのみをラップするというハードコーディングされた振る舞いの代わりに、属性検索で見つかったオブジェクト(上記の例だと関数f)ごとにラッピングするようになった。もしオブジェクトが見つかると、__get__と呼ばれる特殊なメソッド名を持つ、「デスクリプタ」と呼ばれるオブジェクトが返される。次に__get__メソッドが呼ばれ、属性検索の結果として、このメソッドの返値が使用される。もしオブジェクトが__get__メソッドを持っていない場合には、それがそのまま返される。インスタンス属性検索コード内に特別な処理を行う関数オブジェクトを作らずに、関数オブジェクトをラッピングして返すという今まで通りの振る舞いにするために、関数オブジェクトには、以前のコードと同じようなラッパーを返す、__get__メソッドが追加された。このデフォルトのラッパー以外にも、ユーザが自由に__get__というメソッドを持つ他のクラスを定義し、インスタンス属性検索中でクラス辞書の中から発見された場合に、好きなようにラッピングすることもできるようになった。

属性検索コンセプトを一般化するのに加え、属性の設定と削除の操作にも、このアイディアを拡大して適用した。x.a = 1del x.aなど、今までと同じような割り当て操作を使用することができる。このような操作が行われた時に、"a"という属性がインスタンス辞書ではなく、インスタンスのクラス辞書の中で発見された時に、クラス辞書に保持されたオブジェクトに__set____delete__という特別メソッドがないかどうかチェックされる。(__del__というメソッドはまったく別の意味で既に使用されている。そのため、これらのメソッドを再定義することによって、デスクリプタオブジェクト属性の取得、設定、削除の操作の時にどのような処理が行われるかを、完全に制御することができる。しかし、デスクリプタインスタンスが、インスタンス辞書ではなく、クラス辞書内に設定された時にだけ適用されるという点は、重要なので最後にもう一度強調しておきたい。

staticmethod, classmethod, property

Python 2.2からは、classmethod, staticmethod, propertyという、新しいデスクリプタのメカニズムに関連する、3つのクラスが追加された。classmethodstaticmethodは、関数オブジェクトに関するシンプルなラッパで、保持している関数オブジェクトの呼び出し方が通常とは異なるラッパーを返す、__get__メソッドが実装されている。例えば、staticmethodのラッパーは、引数リストに変更をいっさい加えずに関数を呼び出す。classmethodのラッパーは、インスタンスそのものではなく、インスタンスのクラスを引数の先頭に追加してから関数を呼び出す。呼び出されるのがインスタンス経由であっても、クラス経由であっても、それぞれの引数は一緒となる。

propertyクラスは、"属性"に対する値の設定と、"属性"からの読み込みに関する対となる2つのメソッドを持つようなラッパーを生成する。例えば次のようなクラスがあったとする。

class C(object):
   def set_x(self, value):
       self.__x = value
   def get_x(self):
       return self.__x

propertyラッパーを使うと、属性"x"にアクセスされたときに、値の読み込みと設定に、ここで定義されたget_x, set_xメソッドが暗黙的に呼び出されるようにすることができる。

最初にclassmethod, staticmethod, propertyが導入されたときには、これらを簡単に扱える、特別な文法がなかった。そのときは、新しい文法(常に激しい議論が巻き起こる)と一緒に新しい機能を導入しようとすると、議論が収束しなくなって、導入できなくなると考えられたので、機能の追加だけが行われた。そのため、この機能を使用する場合には、通常通りクラスとメソッドを定義したあとに、メソッドをラップするための追加の文を追加する必要があった。

class C:
   def foo(cls, arg):
       ...
   foo = classmethod(foo)
   def bar(arg):
       ...
   bar = staticmethod(bar)

プロパティについても、同様の作法に従っていた。

class C:
 def set_x(self, value):
    self.__x = value
 def get_x(self):
    return self.__x
 x = property(get_x, set_x)
デコレータ

デスクリプタのやり方の不都合な点は、メソッド定義の最後まで読まないと、そのメソッドが静的メソッドが、クラスメソッドか、あるいはその他のユーザ定義の属性を持つメソッドか特定できないという点である。Python 2.4からは、最後に新しい文法が導入され、次のように書くことができるようになった。

class C:
 @classmethod
 def foo(cls, arg):
    ...
 @staticmethod
 def bar(arg):
    ...

@式 というのを、関数定義の前の行に書くことができるようになった。この構文を、デコレータと呼ぶ。__get__を実装したラッパーを作成するデスクリプタと混同しないようにして欲しい。デコレータ構文の文法(Javaのアノテーションから派生)に関しての議論は、「BDFL宣告」によって文法が決定されるまで、延々と続いた。(David BeazleyはBDFLと言う用語の歴史に関しては、私が書いたものとは別々に書いている)。

デコレータ機能は、言語の機能の中で、もっとも成功したものとなった。「うまくいけばここまで広がるだろう」と予想していた範囲いっぱいまで、幅広くカスタムデコレータが使用された。特にウェブフレームワークはこの文法の使用方法について、さまざまな発見をして応用された。この成功を受けて、Python 2.6からは、この文法は関数定義だけではなく、クラス定義でも使用できるように拡張された。

スロット

デスクリプタの導入によって可能になった別の拡張機能としては、クラスの__slots__属性がある。例えば、次のようにクラス宣言が行える

class C:
 __slots__ = ['x','y']
 ...

スロットが定義されると、いくつかのことが行われる。まず最初に、リストに定義されたのと同じ名前の属性しか、オブジェクトに定義できないように制限される。次に、属性が固定されると、それ以上はインスタンス辞書に属性を保持する必要がなくなるため、__dict__属性が削除される。ただし、ベースクラスにはそれがあり、__slots__を利用しないサブクラスで利用される。__dict__の代わりに、配列を使用して、予約された場所に属性が保存される。そのため、すべてのスロットの属性は、それぞれの属性が格納される配列のインデックスを知っている、デスクリプタのオブジェクトが割り当てられる。この機能の実装は、完全にC言語で構築されているため、とても効率が良い。

中には、__slots__を導入した目的が、属性名を制限することによるコードの安全性の向上であると誤解している人もいる。実際には、私の究極の目標はパフォーマンスであった。導入の動機としては、__slots__はデスクリプタの面白い応用例であったから、というのもあったが、これらの新スタイルクラスに導入された変更は、パフォーマンスに対して深刻な影響を与えるのを恐れていたからである。特に、データデスクリプタを適切に動作させるには、オブジェクトの属性に対するあらゆる操作をする前に、データデスクリプタの場合には、まずその属性があるかどうか、クラス辞書を先に見に行く必要がある。その場合には、手動でインスタンス辞書を操作する代わりに、デスクリプタが使用されて属性アクセスが行われる。しかし、このようなチェックを追加する場合には、インスタンス辞書にアクセスする前に、追加の検索が実行されるということを意味している。スロットを利用することでパフォーマンスを向上させることができるため、万が一、新スタイルクラスを導入して、そのようにパフォーマンスの劣化で失望した場合に利用することができる。後になって(パフォーマンスの劣化が思ったよりも少なくて)、不必要であることが分かったが、その時にはもう削除するには遅かった。もちろん、適切に使用すれば、スロットはパフォーマンスを実際に増加させられる。特に、小さいにオブジェクトが大量に作成される場面では、メモリの使用量の削減によって、大きくパフォーマンスは向上する。

次の投稿では、Pythonのメソッド解決順序(MRO)の歴史に触れてみたいと思う。