旧それなりブログの跡地、画像やスタイルやJSなどが壊れてることがあります。

Pythonクックブックを読んでいる(2)

2009年2月21日

<< 前回 |
次回 >>

前回 から引き続き。
今回は、「2章 ファイル」だけを読みました。

「オライリー本は1日1章まで」

この標語が無ければ1日で全部読んでやるのに!

1. fileオブジェクトをそのままループできる
こんな風に書けるそうで。

f = open('/path/to/filename', 'r')
for line in f: print line

fileオブジェクトはジェネレータなので、
readやreadlinesで一回で全部読み込むのとは違い、
メモリ消費が少なくて済むというメリットがある。
超巨大ファイルを処理する場合は、こっちの方がいいすな。

2. fileへの書き込みが保障されるのはcloseした時
そういえば、過去自分が書いたバッチの話なんですが、
“a”モードで開いたファイルに対して、closeなしに延々追記をしてたときに、
実際にHD上のテキストファイルに反映されるのが、スクリプトの進行より遅かったことがある。
こういう仕組みだったのか。

3. str.replace

print "abcdeabcde".replace("b", "B") # -> "aBcdeaBcde"

このメソッド知らなかった・・・。
同じことするのに、re.subとかでやってたぜ金返せ!

4. stdin, stdout
標準入力/標準出力制御をできる。
例えば標準入力の場合は、こんな風に書けば

for line in sys.stdin: print line.rstrip()

OSから標準入力を受け付けることができる。

$echo "111\n222\n333" | ./filename.py

なお、sys.stdin, sys.stdout 両方ともfileライクオブジェクト。

5. timeitモジュール
簡単なスクリプトの実行時間計測モジュール。
Pythonソースを文字列で渡さないといけないのが、やや気持ち悪いけど、
簡単なスクリプト用としては、これがベストだろうなぁ。

と、テストがてら、前回の文字列連結の時間計測をしてみた。

import timeit
source = """
s = "1" + ", 2" + ", 3" + " da---!"
"""
timer = timeit.Timer(stmt=source)
print "join: ", timer.timeit(10000) # 試行回数
source = """
s = "%s, %s, %s da---!" % (1, 2, 3)
"""
timer = timeit.Timer(stmt=source)
print "format: ", timer.timeit(10000)

じゃん、結果!

join:  0.0010929107666
format:  0.0233690738678

・・・あれっ?フォーマットの方が遅いんだけど・・・・・
・・・・・・ま、まぁいいや、見なかったことにしよう・・・。
(つーか、timeitの使い方が間違ってたら元も子もないな)

6. os.tmpfile()
一時ファイルを作成できる、一時ファイルはcloseするとGC対象になる。
使いどころは、巨大データをメモリ上から退避させて、ゆっくり処理する時とかだろうか。

tf = os.tmpfile()
# 少しずつ膨れ上がるデータをメモリから退避
for c in "1GB data": tf.write(c)
# 読み込みのためにファイルポインタを頭に戻す
tf.seek(0)
# 今度は少しずつ先のファイルを読み込み
new_data = ""
while True:
c = tf.read(1)
new_data += c.replace("G", "M")
if not c: break
tf.close()
print new_data # -> "1MB data"

こんな感じ?
あれ、closeしないとHD上への書き込みは保存されないんだっけか・・・?

・・・と、ググったけど、tmpfileを使ったサンプルが出てこないのでとりあえず保留。
実際使うときになったら、標準モジュールとかDjangoとかから探そうっと。

7. os.walk()
指定パスから、再帰的に全てのファイルとディレクトリを返してくれる。
こりゃあ、便利だねっ!
同じような関数を自分で書いちゃったなー。

以上。

色々、挙動が不明の場所もありましたが、
そこはそれ、スルー力には自信がある。