Python バージョン 3 は、Python 3000 または Py3K (Microsoft® Windows® 2000 オペレーティング・システムをもじったニックネーム) として知られており、Guido van Rossumによる汎用プログラミング言語の最新バージョンです。コア言語に多くの改善が行われていますが、この新バージョンは 2.x シリーズとの後方互換性がありません。それ以外の変更点は長年期待されていたものであり、例えば次のようなものがあります。
- 真の割り算 (例えば1/2 は .5 を返します)。
long型とint型は 1 つの型に統合され、末尾に付けられていた L はなくなりました。True、False、Noneがキーワードになりました。
この記事は Python 3 に関するシリーズの第 1 回として、新しい print() 関数、input()、入出力 (I/O) に関する変更、新しい byte データ型、そしてストリングとストリング・フォーマットへの変更について説明し、最後に組み込みの dict 型に対する変更について説明します。この記事は、既に Python をよく理解していて変更点に関心があるものの、PEP (Python Enhancement Proposal) の長いリストを 1 つ 1 つ調べるのは避けたいと思っているプログラマーを対象としています。(PEP へのリンクは下記の「参考文献」にあります)。
Python 3 では、print "hello" と入力するのをやめ、print("hello") と入力するように指の訓練をやり直す必要があります。なぜなら Python 3 では print は関数であり、命令ではなくなったからです。もちろん私も、これが苦痛なことはわかっています。私が知っている Python プログラマーは全員、バージョン 3 をインストールした途端に「不正な構文 (incorrect syntax)」というエラーが表示され、苦痛の叫び声を上げています。私も 2 文字追加されたことが悩ましいことであるのは知っており、またこれによって後方互換性が失われることも知っています。しかしこうすることにはメリットがあるのです。
例えば標準出力 (stdout) をログにリダイレクトする場合を考えてみてください。下記の例は追加用の log.txt ファイルを開き、そのオブジェクトを fid に割り当てます。次に print>> を使ってストリングを fid ファイルにリダイレクトします。
>>>fid = open("log.txt", "a")
>>>print>>fid, "log text"
|
もう 1 つの例は標準的なエラー (sys.stderr) にリダイレクトする場合です。
>>>print>>sys.stderr, "an error occurred" |
この 2 つの例はどちらも適切ですが、もっと良いソリューションがあります。新しい構文では、単純に print() 関数のキーワード引数 file に値を渡します。下記はその一例です
>>>fid = open("log.txt", "a")
>>>print("log.txt", file=fid)
|
このコードの方が構文はずっとスマートです。もう 1 つのメリットは、sep キーワード引数にストリングを渡すことで区切り文字を変更でき、また別のストリングを end キーワード引数に渡すことで終了文字を変更できることです。区切り文字を変更するためには以下のようにします。
>>>print("Foo", "Bar", sep="%")
>>>Foo%Bar
|
一般的に、新しい構文は以下のようになります。
print([object, ...][, sep=' '][, end='endline_character_here'][, file=redirect_to_here]) |
ここで、大括弧 ([]) の中のコードはオプションです。デフォルトで、print() を呼び出すこと自体によって改行文字 (\n) が追加されます。
Python バージョン 2.x では、raw_input() は標準入力 (sys.stdin) からの入力を読み取り、最後に付いている改行文字が削除されたストリングを返します。次の例は raw_input() を使ってコマンド・プロンプトからストリングを取得し、その値を quest に割り当てます。
>>>quest = raw_input("What is your quest? ")
What is your quest? To seek the holy grail.
>>>quest
'To seek the holy grail.'
|
これとは対照的に、Python 2.x の input() 関数は有効な Python 式 (3+5 など) を想定します。
元々は、input() と raw_input() のどちらも Python に組み込みの名前空間から完全に削除され、そのため何らかの入力機能を持つ import が必要だと言われていました。これは教育的に不健全に思えます。つまり単純に以下のように記述していたものが、
>>>quest = input("What is your quest?")
|
突然次のように変ってしまうのです。
>>>import sys
>>>print("What is your quest?")
>>>quest = sys.stdin.readline()
|
これは単なる入力のためには冗長すぎ、初心者には長々とした説明をしなければなりません。つまり、モジュールやインポートとは何か、またストリングの出力やドット演算子とは何かといったことを教えなければなりません。(これはあまりにも Java™ 言語に似すぎているように感じられます・・・) そこで Python 3 では、raw_input() は input() と名前が変えられ、また標準入力からデータを取得するためにインポートは必要ありません。バージョン 2.x の input() 機能を維持する必要がある場合には、eval(input()) を使えば同じように動作します。
新しいデータ型であるバイト・リテラルは、bytes オブジェクトと同様に、バイナリー・データを保管するために使われます。bytes オブジェクトは 0 と 127 (つまり ASCII のみの文字) の間の整数の不変シーケンスです。実はこれは、バージョン 2.5 の bytearray オブジェクトの不変バージョンなのです。バイト・リテラルは、先頭に b が付いたストリングです (例えば b'byte literal' など)。バイト・リテラルを評価すると、新しい bytes オブジェクトが生成されます。新しい bytes オブジェクトを bytes() 関数を使って作成することもできます。bytes オブジェクトを作成するためには以下のようにします。
bytes([initializer[, encoding]]) |
例えば以下のようにすると、
>>>b = (b'\xc3\x9f\x65\x74\x61') >>>print(b) b'\xc3\x83\xc2\x9feta' |
bytes オブジェクトが作成されますが、これでは冗長です。なぜなら bytes オブジェクトは単純にバイト・リテラルを割り当てるだけで作成できるからです。(私はこうすることもできることを示したかっただけであり、実際にこうするように推奨しているわけではありません。) もし iso-8859-1 エンコーディングを使いたい場合には、以下のようにすることもできます。
>>>b = bytes('\xc3\x9f\x65\x74\x61', 'iso-8859-1')
>>>print(b)
b'\xc3\x83\xc2\x9feta'
|
初期化子がストリングの場合にはエンコーディングを指定する必要があります。初期化子がバイト・リテラルの場合にはエンコーディング・タイプを指定する必要はありません。バイト・リテラルはストリングではないことを忘れないでください。しかしストリングと同様、以下のようにバイト・リテラルを連結することができます。
>>>b'hello' b' world' b'hello world' |
bytes() メソッドを使うと、バイナリー・データとエンコードされたテキストの両方を表現することができます。bytes から str に変換するためには、bytes オブジェクトをデコードする必要があります (これについては後ほど説明します)。バイナリー・データをデコードするためには以下のように decode() メソッドを使います。
>>>b'\xc3\x9f\x65\x74\x61'.decode() 'ßeta' |
また、バイナリー・データをファイルから直接読み取ることもできます。例えば以下のコードは、
>>>data = open('dat.txt', 'rb').read()
>>>print(data) # data is a string
>>># content of data.txt printed out here
|
ファイル・オブジェクトを読み取るためにバイナリー・モードでファイルを開き、ファイル全体を読み取ります。
Python には、バージョン 2.x の unicode 型と似た動作をするストリング型 (str) があります。言い換えると、すべてのストリングは unicode ストリングです。また、(非ラテン語系テキストのユーザーには非常に便利なことに) ASCII ではない識別子が許可されるようになりました。以下はその一例です。
>>>césar = ["author", "consultant"] >>>print(césar) ['author', 'consultant'] |
これまでのバージョンの Python では、repr() メソッドは 8 ビットのストリングを ASCII に変換しました。以下はその一例です。
>>>repr('é')
"'\\xc3\\xa9'"
|
Python 3 では、repr() メソッドは unicode ストリングを返します。
>>>repr('é')
"'é'"
|
これは先ほど触れたように、組み込みのストリング型です。
ストリング・オブジェクトとバイト・オブジェクトには互換性はありません。バイト・オブジェクトをストリングで表現したい場合には、そのオブジェクトの decode() メソッドを使います。逆に、ストリングのバイト・リテラルが必要な場合には、そのストリング・オブジェクトの encode() メソッドを使います。
多くの Python プログラマーは、ストリングのフォーマットを設定するための組み込みの % 演算子は制約が多すぎると感じていました。それは、以下の 2 つの理由からです。
- % 演算子は二項演算子であり、引数は最大でも 2 つしか取れません。
- ストリングのフォーマット設定用の引数以外に引数がある場合には、他のすべての引数をタプルまたはディクショナリーの中に詰め込まなければなりません。
このスタイルは多少柔軟性に欠けるため、Python 3 ではストリングのフォーマットを設定するために新しい方法を導入しています。(% 演算子も string.Template モジュールも、バージョン 3 には残っています。) Python 3 では、ストリング・オブジェクトは位置引数とキーワード引数を受け付ける format() メソッドを持ち、これらの引数は置換フィールドに渡されます。置換フィールドはストリングの中の中括弧 ({}) で表現されます。置換フィールドの中にある要素は単純にフィールドと呼ばれます。以下に示すのはその単純な一例です。
>>>"I love {0}, {1}, and {2}".format("eggs", "bacon", "sausage")
'I love eggs, bacon, and sausage'
|
フィールド {0}、{1}、{2} には format() メソッドの位置パラメーターである eggs、bacon、sausage が渡されます。以下の例は format() を使ってキーワード引数を渡すことでフォーマットを設定する方法を示しています。
>>>"I love {a}, {b}, and {c}".format(a="eggs", b="bacon", c="sausage")
'I love eggs, bacon, and sausage'
|
以下に示すのは位置パラメーターとキーワード引数とを組み合わせた別の例です。
>>>"I love {0}, {1}, and {param}".format("eggs", "bacon", param="sausage")
'I love eggs, bacon, and sausage'
|
キーワードではない引数をキーワード引数の後に置くのは構文エラーだということを忘れないでください。中括弧をエスケープするためには、以下のように中括弧を二重にします。
>>>"{{0}}".format("can't see me")
'{0}'
|
この場合、位置パラメーター can't see me は出力されませんが、これは出力用のフィールドがないからです。こうしてもエラーにはならないことに注意してください。
format() という新しい組み込み関数は 1 つの値のフォーマットを設定します。以下はその一例です。
>>>print(format(10.0, "7.3g"))
10
|
つまり g は汎用 (general) フォーマットを表し、固定長の数字を出力します。ドットの前にある最初の数字は最小桁数を指定し、ドットの後にある数字は精度を指定します。この記事ではフォーマット指定子に関する完全な構文の説明は省略しますが、詳しい情報へのリンクは「参考文献」セクションを参照してください。
3.0 での、もう 1 つの大きな変更は、dict.iterkeys() メソッドと dict.itervalues() メソッド、そして dict.iteritems() メソッドがディクショナリーから削除されたことです。これらの代わりに .keys()、.values()、.items() を使いますが、これらは (キーまたは値のコピーであるリストの代わりに) 軽量で set のようなコンテナー・オブジェクトを返すように変更されています。これによるメリットは、キーや項目に対して set 操作を行うことができ、キーや項目をコピーする必要がないことです。以下はその一例です。
>>>d = {1:"dead", 2:"parrot"}
>>>print(d.items())
<built-in method items of dict object at 0xb7c2468c>
|
注: Python では、set は一意の要素を順不同で集めたものです。
ここでは 2 つのキーと値を持つディクショナリーを作成し、次に d.items() の値を出力しています。そうすると値のリストではなくオブジェクトが返されます。ある要素のメンバーかどうかのテストは set オブジェクトの場合と同じように行うことができます。
>>>1 in d # test for membership True |
以下に示すのは dict_values オブジェクトの項目に対して繰り返し処理を行う例です。
>>>for values in d.items(): ... print(values) ... dead parrot |
しかし、どうしても値のリストが必要な場合には、返された dict オブジェクトをキャストすることでいつでもリストが得られます。以下はその一例です。
>>>keys = list(d.keys()) >>>print(keys) [1,2] |
I/O のための新しいメカニズムを説明する前に、ABC (abstract base class: 抽象基底クラス) について復習する必要があります。ABC の扱い方の詳細についてはこのシリーズの第 2 回に説明します。
ABC はインスタンス化できないクラスです。ABC を使うためには、ABC を継承し、継承したサブクラスの抽象メソッドをオーバーライドする必要があります。あるメソッドの前に修飾子 @abstractmethod があると、そのメソッドは抽象メソッドです。新しい ABC フレームワークには、抽象プロパティーを定義するための @abstractproperty 修飾子も用意されています。この新しいフレームワークを利用するためには、標準ライブラリー・モジュール abc をインポートします。リスト 1 は簡単な例を示しています。
リスト 1. 単純な抽象基底クラス
from abc import ABCMeta
class SimpleAbstractClass(metaclass=ABCMeta):
pass
SimpleAbstractClass.register(list)
assert isinstance([], SimpleAbstractClass)
|
register() メソッドの呼び出しはクラスを引数に取り、ABC を、登録されたクラスのサブクラスにします。これを確認するために最後の行で assert 命令を呼び出します。リスト 2 は修飾子を使う別の例です。
リスト 2. 修飾子を使って実装された抽象基底クラス
from abc import ABCMeta, abstractmethod
class abstract(metaclass=ABCMeta):
@abstractmethod
def absMeth(self):
pass
class A(abstract):
# must implement abstract method
def absMeth(self):
return 0
|
これで ABC について理解できたので、新しい I/O システムの説明を続けましょう。これまでの Python のリリースには、風変わりでも重要な関数、例えばストリームのようなオブジェクトに対する seek() などがありませんでした。ストリームのようなオブジェクトというのは read() メソッドと write() メソッドを持つファイルのようなオブジェクトであり、例えばソケットやファイルなどです。Python 3 にはストリームのようなオブジェクトに対して複数の I/O レイヤー (そのままの I/O レイヤー、バッファー付き I/O レイヤー、そしてテキスト I/O レイヤー) があり、それぞれのレイヤーには独自の ABC が実装と共に定義されています。
io.open(fileName)) を呼び出すこともできますが、ストリームを開くにはやはり組み込みの open(fileName) 関数を使います。そうすることで、バッファリングされたテキスト・ファイルが返されます。つまり read() と readline() によってストリングが返されるのです。(Python 3 ではすべてのストリングが unicode であることを忘れないでください。) また、バッファリングされたバイナリー・ファイルを open(fileName, 'b') という形式を使って開くこともできます。この場合、read() はバイトを返しますが、readline() を使うことはできません。
組み込みの open() 関数を使うには以下のようにします。
open(file,mode="r",buffering=None,encoding=None,errors=None,newline=None,closefd=True) |
mode に指定できるのは以下のモードです。
r: 開いて読み取るモードw: 開いて書き込むモードa: 開いて追加するモードb: バイナリー・モードt: テキスト・モード+: ディスク・ファイルを開いて更新するモードU: 汎用の改行モード
デフォルトのモードは rt、つまり「開いてテキスト・モードで読み取る」です。
buffering というキーワード引数を付けると、バッファリング方法を決定するための下記の 3 つの整数の 1 つを受け付けることになります。
0: バッファリングをオフにする1: 行バッファリング> 1: フル・バッファリング (デフォルト)
デフォルトのエンコーディングはプラットフォームに依存します。ファイルを閉じるための記述子、つまり closefd は、True または False になります。False の場合、ファイルが閉じられた後にファイル記述子が保持されます。ファイル名を指定しても動作しない場合には、closefd が True に設定されているはずです。
open() によって返されるオブジェクトは設定されたモードに依存します。表 1 は戻り型を示しています。
表 1. 開くモードによる戻り型の違い
| モード | 返されるオブジェクト |
|---|---|
| テキスト・モード |
TextIOWrapper
|
| バイナリー |
BufferedReader
|
| バイナリーで書き込み |
BufferedWriter
|
| バイナリーで追加 |
BufferedWriter
|
| 読み書きモード |
BufferedRandom
|
注: テキスト・モードは w、r、wt、rt などです。
リスト 3 の例はバッファリングされたバイナリー・ストリームを開いて読み取ります。
リスト 3. バッファリングされたバイナリー・ストリームを開いて読み取る
>>>import io
>>>f = io.open("hashlib.pyo", "rb") # open for reading in binary mode
>>>f # f is a BufferedReader object
<io.BufferedReader object at 0xb7c2534c>
>>>f.close() # close stream
|
BufferedReader オブジェクトを使うと、いくつかの便利なメソッドにアクセスすることができます (一部を挙げるだけでも、isatty、peek、raw、readinto、readline、readlines、seek、seekable、tell、writable、write、writelines などがあります)。完全な一覧を見るためには BufferedReader オブジェクトに対して dir() を実行します。
Python コミュニティーがバージョン 3 を受け入れるかどうかは誰にもわかりません。後方互換性がないということは、2 つの異なるバージョンを並行してサポートするということです。一部のプロジェクト開発者は、たとえバージョン 2 から 3 へのコンバーターがあったとしても彼らのプロジェクトを移行したくないと思うかもしれません。個人的には、私は Python バージョン 2 から 3 への移行は基本的に、いくつかのことを学び直すことだということに気付きました。もちろんこの移行は、例えば Python から Java 言語や Perl 言語に移行するほどの劇的な変更ではありませんでした。多くの変更は長年待ち望まれていたものです (例えば真の割り算や dict に対する変更など)。print() を実行する方が Java での System.out.println() よりも遥かに容易であるため、学習期間は短くてすみ、しかも多くのものを得ることができます。
ブロゴスフィアのエントリーを読んでみると、多くの Python 主義者達は、いくつかの変更 (例えば後方互換性をなくしたこと) は約束違反だと考えているようです。ラムダは元々削除される予定でしたが、残っており、しかも元の形式のままです。変更されていない内容の完全な一覧は Python のコア開発のサイトを参照してください。冒険心に満ちた人ならば、PEP を調べれば詳細な情報を見つけることができるはずです。
このシリーズの次回の記事では、より高度な話題、例えばメタクラス構文、抽象基底クラス (ABC)、修飾子、整数リテラルのサポート、基底型、例外などについて説明する予定です。
学ぶために
- Python のコア開発のサイトにはフォーマット指定子に対する完全な構文が説明されています。
- Python 3 PEP のうち、関係する項目を読んでください。
- PEP 3111: Python 3000 に組み込みの単純な入力
- PEP 3116: 新しい I/O
- PEP 3138: Python 3000 でのストリング表現
- PEP 3112: Python 3000 でのバイト・リテラル
- PEP 3137: 不変バイトと可変バッファー
- PEP 3106: dict.keys()、.values()、.items() の変更
- PEP 3108: 標準ライブラリーの再構成
- PEP 3100: Python 3.0 の計画に関する雑多な事項
- ウィキペディアでメタクラスの項目を見てください。
- 抽象クラスを含めたコンピューターのクラスの説明をウィキペディアで見てください。
- Guido van Rossum のエッセイを読んでください。
- Python での、一意の要素を順不同で集めたもの、つまり set についての説明を読んでください。
- developerWorks の Linux ゾーンには、(Linux が初めての開発者を含めた) Linux 開発者のためのリソースが豊富に用意されています。最も人気のあった記事とチュートリアルの一覧もご覧ください。
- developerWorks には他にも Linux に関するヒントやチュートリアルが豊富に用意されています。
- developerWorks technical events and webcasts で最新情報を入手してください。
製品や技術を入手するために
- Python の最新バージョンを入手してください。
- developerWorks から直接ダウンローできる IBM ソフトウェアの試用版を利用して皆さんの次期 Linux プロジェクトを構築してください。
議論するために
- ブログやフォーラム、ポッドキャスト、そして spaces などをとおして developerWorks のコミュニティーに加わってください。
