連載
» 2009年01月31日 00時00分 公開

よりPythonicなPythonを目指して(前編):Python 3が後方互換性を捨ててでも求めたもの (1/2)

Python 3.0では、Python 2で書かれたスクリプトが動かなくなるような実装が行われた。なぜ、後方互換性を崩してまで大きな仕様変更を行ったのか。それは、PythonがよりPythonらしくあるためだ。

[柴田淳,ウエブコア株式会社]

 2008年12月4日、Python 3.0がリリースされました。これまで「Python 3000」や「Py3k」という愛称で呼ばれ、Pythonの次期メジャーバージョンとして開発されていたものです。

 メジャーバージョンアップといっても、基本的な文法、インデントを使ったブロック表記や基本的な機能の多くはPython 2から引き継いでいます。Pythonの持つシンプルで一貫性のある設計思想を受け継ぎ、よりPythonicなPythonへと言語をステップアップさせるための重要なリリースです。

 Python 3はPython 2と設計思想的に連続的な位置付けにある言語ですが、一点だけ大きな違いがあります。後方互換性を崩す機能追加や仕様変更が多く実装されているのです。

 これまでは、バージョンアップを行うときに後方互換性が最大限考慮されてきました。理にかなっていて、多くの開発者に利する機能追加や仕様変更でも、「後方互換性を崩すから」という理由で採用されなかったものが、Pythonの歴史にはたくさんあります。

 後方互換性を崩す機能追加は痛みを伴い、しばしば開発者に無用な苦労を強いることを、創始者のグイド・ヴァンロッサム(Guido van Rossum)を始めとするPythonの開発チームはよく知っています。

 Python 3.0では、Python 2の頃に書かれたスクリプトの多くはそのままでは動きません。言語仕様や組み込み型、標準ライブラリにメスが入り、ドラスティックな仕様変更が行われているからです。

 例えばPython 3.0では、辞書型のいくつかのメソッド−辞書のキーを検査する「has_key()」など−が削除されています。それは、Python 2.3からは辞書型に対して「in」演算子が使えるようになり、「dic.has_key('foo')」と等価なコードを「'foo' in dic」と記述できるようになっていたからです。

 同じ処理を実行するのに複数の方法が存在することをPythonでは嫌います。そのため、辞書だけでなく文字列やリストなどの要素を検査する、より一般的な「in」演算子を使う方法が残され、has_key()メソッドが削除されたのです。

 この例のように、Python 3では「古い方法論で作られた機能を取り除き、将来に重複が発生することを防ぐ(to reduce feature duplication by removing old ways of doing things)」という考えの下、いくつかの機能が意図的に削られています。

 後方互換性を崩す仕様変更は、「誰もが正しいと考える、たった1つの方法をできる限り採用する(There should be one-and preferably only one-obvious way to do it)」というPythonの設計思想を、より高次元で実現するために必要なことだったのです。

 この記事では、Python 3の新機能について概観しながら、なぜ後方互換性を崩す仕様変更が必要だったのかについて重点的に解説します。

print()関数 ― 文から式へ

 Pythonは、ほかのスクリプト言語やプログラミング言語に比べて、「文」と「式」を明確に区分けする言語といえます。

 Pythonでは、「評価式」「関数やメソッドの呼び出し」「オブジェクトのリテラル表記」などが「式」として分類されます。式は1行に複数置くことができます。「リスト内包表記」も式の一種です。

 一方、「if文」「for文」「try〜except文」「import文」「代入文」などが文として分類されます。基本的に、1行には複数の文を書くことができません。いい換えると、文は改行を伴います。Pythonの「文」には、フロー制御やモジュールのインポートなど、プログラムの構造を記述するために重要な要素が整理されていることが分かります。

 また、「文」に改行が必要なことは、可読性の向上に一役買っています。プログラムの構造を記述するために使われる部分が1行に記述されるため、プログラムを目で見たときに、プログラムの構造を把握しやすくなっているのです。

 さらに、「if」や「for」といった式を表記するためのキーワードは予約語として登録され、変数名として使うことができなくなっています。

 Python 2世代の「文」の中で、異彩を放っているのが「print文」です。特にプログラムの構造に影響を与えるわけでもなく、与えられた文字列を標準出力に出力するという特定の用途に利用する機能が「文」として定義されているわけです。

 関数的な機能のくせに予約語に入っているのも「空気が読めない」としかいいようがありません。グイドはprint文の実装が間違いであることを早くから認めていて、後方互換性を崩す仕様変更が行われるのなら関数にすると公言していました。

 最初に「文」として実装してしまったため、後方互換性を守るという観点からずっと仕様を変更できずにいたのです。Python 3.0ではprintが関数として実装され、やっと彼の念願がかなったというわけです。同時に、printは予約語からも削除されました。

 print()が関数として実装されたことは、ほかにも利点をもたらしています。Python 2までのprint文で、出力先を指定する仕様はアドホックで覚えづらいと、悪い意味で定評がありました。

 例えば、Python 2で、print文の出力をファイルに変更するためのコードは以下のようになります。

>>> f = open("somefile.txt", "a")
>>> print >>f, "Spam and Egg and Spam"

 一方、Python 3.0では以下のように、出力先を引数で指定します。すっきりしていて、覚えやすい仕様といえます。

>>> f = open("somefile.txt", "a")
>>> print("Spam and Egg and Spam", file=f)

 Python 3.0のprint()関数は、fileのほかにも引数をとることができます。例えば、endという引数を指定すると、print()関数の末尾に表示する文字を指定できます。以下のコードは、Python 2で「print "foo",」と書いたときと同じ動作をします。

>>> print("foo", end='')

 printは特にインタラクティブモードでテストを行っているときに多用します。Python 3を使い始めるときに、ついつい関数呼び出しの丸カッコを付け忘れて文法エラーを出してしまうかもしれません。Python 2.6が持つPython 3互換モードを使うなどして、いまのうちにprint()関数に慣れる訓練をしておいた方が良いでしょう。

 print文をたくさん含む既存のコードを持っている人は、コードコンバータを使いましょう。すべてのprint文を間違いなくprint()関数に変換してくれます。

       1|2 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

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

メールマガジン登録

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