7. 入力と出力

プログラムの出力を現す方法はいくつもある。 データは、人間可読な形式で印字することも、 あるいは将来の使用のためにファイルに書き込むこともできる。 この章はいくつかの可能性を議論する。

 
7.1 よりファンシーな出力の書式化

これまでのところ私たちは値を書く二つの方法、式文 (expression statement)print 文を見てきた。 (もう一つの方法はファイルオブジェクトの write() メソッドを 使う方法だ。標準出力ファイルは sys.stdout として参照できる。 これに関する詳細については Library Reference を見られたい)

しばしば、出力の書式化に対し、 単純に値をスペースで区切って印字する以上の制御が欲しくなることだろう。 出力を書式化する方法は二つある。 第一の方法は、自分自身で文字列の処理をすべて行う方法だ。 文字列のスライスと連結の演算を使えば、 想像し得る限りのレイアウトを造りだせる。 標準モジュール string には、 与えられた桁幅に文字列をそろえる便利な演算がある。 これらを簡単に説明する。 第二の方法は、% 演算子を、文字列を左項として使う方法だ。 % 演算子は左項を sprintf() スタイルの書式文字列 のように解釈して右項に適用し、その書式化演算から得られた文字列を返す。

もちろん、一つの問題が残っている。どうやって値を文字列へ変換するのだろうか? 幸い Python にはどんな値でも文字列へ変換する方法がある。 値を repr() もしくは str() 関数に渡すせばよい。 逆クォート (``) ではさむのは repr() と等価であるが、 利用は推奨しない。

str() 関数は値をかなり人間に判読可能な表現で返すようになっている 一方 repr() 関数はインタープリター(あるいは等価なシンタック スがない場合に SyntaxError を強要するだろう)によって読むこ とを目的とした表現を生成するようになっている。 人間の利用のための特別な表現を持っていないオブジェクトでは、 str()repr() と同じ値を返す。 リスト、辞書のような数字か構造のような多くの値が、どちらの関数を使用し ても、同じ表現となる。 文字列および浮動小数点数では特有の2つの別個の表現となる。

いくつか例を挙げる。

>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(0.1)
'0.1'
>>> repr(0.1)
'0.10000000000000001'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>>> print s
The value of x is 32.5, and y is 40000...
>>> # 文字列への repr() はクォートとバックスラッシュが付加される:
... hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print hellos
'hello, world\n'
>>> # repr() の引数は Python オブジェクトの場合もある:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"
>>> # 逆クォートは対話セッショで便利:
... `x, y, ('spam', 'eggs')`
"(32.5, 40000, ('spam', 'eggs'))"

下記は2乗と3乗の表を書く二つの方法だ。

>>> import string
>>> for x in range(1, 11):
...     print string.rjust(repr(x), 2), string.rjust(repr(x*x), 3),
...     # 上の行の末尾のコンマに注意
...     print string.rjust(repr(x*x*x), 4)
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000
>>> for x in range(1,11):
...     print '%2d %3d %4d' % (x, x*x, x*x*x)
... 
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

(print が印字しているとき、 コラム間に1個ずつスペースが加えられたことに注意しよう。 print はつねに引数間にスペースを加える)

この例は関数 string.rjust() の使い方を示している。 この関数は、文字列の左側にスペースを詰めることによって、 文字列を指定された幅のフィールドに右ぞろえ (right-justify) する。 似たような関数に string.ljust()string.center() が ある。これらの関数は何も書かず、ただ新しい文字列を返す。 もしも入力文字列が長すぎるときは、切り詰めずにそのまま返す。 これは文章レイアウトをメチャクチャにするが、普通は、 切り詰めてウソの値を書くよりもましだ (もし本当に 切り詰めたいのならば、"string.ljust(x, n)[0:n]") のように つねにスライス演算を加えればよい)。

もう一つの関数 string.zfill() は、 数値文字列の左側をゼロで詰める。これは正と負の符号を正しく扱う。

>>> import string
>>> string.zfill('12', 5)
'00012'
>>> string.zfill('-3.14', 7)
'-003.14'
>>> string.zfill('3.14159265359', 5)
'3.14159265359'

% 演算子を使うとこのようになる。

>>> import math
>>> print 'The value of PI is approximately %5.3f.' % math.pi
The value of PI is approximately 3.142.

文字列の中に複数の書式があるときは、以下の例のように右オペランドとして タプルを渡す必要がある。

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print '%-10s ==> %10d' % (name, phone)
... 
Jack       ==>       4098
Dcab       ==>       7678
Sjoerd     ==>       4127

ほとんどの書式は正確に C と同じように働く。 君は書式に正しい型を渡す必要がある -- しかし、そうしなかったから といって例外を得るだけで、コアダンプはしない。 書式 %s はもっと寛大だ。つまり、もしも対応する引数が 文字列オブジェクトでなければ、組込み関数 str() を使って 文字列へと変換する。 * を使って幅や精度を別個の (整数) 引数として渡すことは サポートされている。 C の書式 %n%p はサポートされていない。

もしも本当に長い書式文字列があって、それを分割したくないとき、 書式化すべき変数を位置ではなく名前で参照できたらすばらしいだろう。 以下のように %(name)format という形式を用いることによって、 それが可能だ。

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % table
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

これは、すべてのローカル変数を収めた辞書を返す 新しい組込み関数 vars() と組み合わせると特に便利だ。

 
7.2 ファイルを読み書きする

open()  は ファイルオブジェクトを返す。 open() は普通、"open(filename, mode)" のように 2引数で使われる。

>>> f=open('/tmp/workfile', 'w')
>>> print f
<open file '/tmp/workfile', mode 'w' at 80a0960>

第1引数はファイル名からなる文字列だ。 第2引数も文字列で、ファイルの使われ方を記述する少数の文字からなる。 mode はファイルが読まれるだけなら 'r' でよい。 書かれるだけなら 'w' でよい (同名の既存ファイルは消去される)。 'a' はファイルを追加書込みのために開くから、そのファイルに書かれる データは自動的に終端に追加される。 'r+' はファイルを読み書き両方のために開く。 mode 引数は省略可能で、省略されたときは 'r' が仮定される。

Windows と Macintosh では、mode'b' を追加すると、 ファイルをバイナリモードで開く。 したがって 'rb', 'wb', 'r+b' のようなモードもある。 Windows はテキストファイルとバイナリファイルを区別していて、 テキストファイルの行末文字は、データが読み書きされるとき、 自動的にわずかばかり改変される。 ファイルデータへのこの暗黙裏の改変は、ASCII テキストファイルには 差しつかえないが、JPEG や .EXE ファイルのようなバイナリデータを ダメにしてしまう。 このようなファイルを読み書きするときは、バイナリモードを使うように十分 気を付けて欲しい。(Macintosh でのテキストモードの正確な意味は、 使用される基底の C ライブラリに依存することに注意するように)

 
7.2.1 ファイルオブジェクトのメソッド

この節のこれ以降の例は、 f というファイルオブジェクトが既に造られていることを仮定する。

ファイルの内容を読み取るには、f.read(size) を呼び出す。 これは、ある量のデータを読み取り、それを文字列として返す。 size は省略可能な数値引数だ。 size が省略されるかまたは負数なら、ファイルの全内容が読み取られて 返される -- もしもファイルが利用マシンのメモリの2倍の大きさでも、 それは利用者の問題だ。 size が非負数ならば、高々 size バイトだけ読み取られて返される。 もし既にファイルの終端に達しているならば、f.read() は 空文字列 ("") を返す。

>>> f.read()
'This is the entire file.\n'
>>> f.read()
''

f.readline() はファイルから1行だけ読み取る。このとき、 改行文字 (\n) が文字列の終端に残される。 改行文字がないのは、ファイルが改行で終わらないときの、 ファイルの最終行だけだ。 これは戻り値からあいまいさをなくす。つまり、 もしも f.readline() が空文字列を返したなら、 ファイルの終端に達している。 しかるに空行は '\n' -- つまり1個の改行だけからなる文字列 -- で 表現される。

>>> f.readline()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''

f.readlines() は、 ファイルの中のデータからなる行すべてを含んだリストを返す。 もしも省略可能な引数 sizehint が与えられたなら、 ファイルからそれだけのバイト数を読み取り、 そしてさらに1行を完成させるに十分なだけ読み取って、 それらから行のリストを作って返す。 これはしばしば、大きなファイル全体をメモリにロードすることなく、 ファイルを行ごとに効率よく読み取るために使われる。 未完成の行が返されることはない。

>>> f.readlines()
['This is the first line of the file.\n', 'Second line of the file\n']

f.write(string)string の内容をファイルに書き込み、 None を返す。

>>> f.write('This is a test\n')

f.tell() はファイルの中でのファイルオブジェクトの現在の位置を 与える整数を返す。これはファイルの先頭からバイトで測った数だ。 ファイルオブジェクトの位置を変更するには、 "f.seek(offset, from_what)" を使う。 位置は、参照点に offset を足して計算される。 参照点は from_what 引数によって選択される。 from_what の値が 0 ならばファイルの先頭から測り、 1 ならば現在のファイル位置を使い、2 ならばファイルの終端を参照点として使う。 from_what は省略可能だ。省略時の値は 0 で、 ファイルの先頭を参照点として使う。

>>> f=open('/tmp/workfile', 'r+')
>>> f.write('0123456789abcdef')
>>> f.seek(5)     # ファイルの第6バイトへ行く
>>> f.read(1)        
'5'
>>> f.seek(-3, 2) # 終端から前へ第3バイトへ行く
>>> f.read(1)
'd'

ファイルの利用が終了したら、f.close() を呼び出してファイルを閉じ、 開いていたファイルに取られていたシステム資源を解放する。 f.close() を呼び出した後は、そのファイルオブジェクトを使おうと しても自動的に失敗することになる。

>>> f.close()
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file

ファイルオブジェクトには、それほど頻繁には使われないが、 isatty()truncate() など、あといくつかのメソッドがある。 ファイルオブジェクトの完全なガイドについては Library Reference を 調べられたい。

 
7.2.2 pickle モジュール

 

文字列はたやすくファイルから読み書きできる。 数は少々骨が折れる。なぜなら read() メソッドが文字列しか 返さないから、'123' のような文字列を受け取ってその数値 123 を 返す string.atoi() のような関数にその文字列を渡してやらなければ ならないからだ。 しかし、リストや辞書やクラスインスタンスのようなもっと複雑なデータ型を 保持しようと思ったら、ことはもっと複雑になる。

Python は、複雑なデータ型を保持するコードを利用者に毎回毎回書かせて デバッグさせるようなことはしない。 そのかわりに pickle という標準モジュールを用意している。 これはほとんどどんな Python オブジェクトをも (ある形式の Python コード でさえも!) 受け取って文字列表現へ変換できるという驚嘆すべきモジュールだ。 この変換過程は pickling (漬け物化) と呼ばれる。 文字列表現からのオブジェクトの再構成は unpickling と呼ばれる。 pickling と unpickling のあいだ、その文字列表現を、ファイルやデータに 格納したり、ネットワーク接続を越えて遠くのマシンに送ったりできる。

オブジェクト x と、 書込み用に開かれているファイルオブジェクト f があると仮定して、 オブジェクトを pickling する最も簡単な方法はたった1行のコードで済む。

pickle.dump(x, f)

オブジェクトを再び unpickling するには、 f が読取り用に開かれているファイルオブジェクトであると仮定して、

x = pickle.load(f)

(これにはいくつか別の方法がある。それらは多数のオブジェクトを pickling したり、 pickling したデータをファイルへ書き込みたくないときに使われる。 pickle の完全なドキュメンテーションについては Library Reference を 調べられたい)

pickle は、ほかのプログラムや将来起動したときの自プログラムから 再利用できるように格納しておける Python オブジェクトを作るための、 標準的な方法だ。 これを表す技術用語は永続オブジェクト (persistent object) という。 pickle はとても広く使われているから、 Python 拡張を書く多くの著者は、行列などの新しいデータ型が 正しく pickling/unpickling できるように気をつけている。

See About this document... for information on suggesting changes.