Pythonクックブック(2章)

2章はファイル操作について

特定の行を読む(linecacheモジュール)

linecacheモジュールを使うと、テキストファイルの各行にランダムにアクセスできる。
linecache.getline(filename, line_number)はline_number行目のデータを返す。
もし、line_number行目がなければ、''を返す。

[kobakoba0723@fedora13-intel64 ~]$ tail -n 1 /etc/passwd
kobakoba0723:x:501:501::/home/kobakoba0723:/bin/bash
[kobakoba0723@fedora13-intel64 ~]$ wc -l /etc/passwd
39 /etc/passwd
[kobakoba0723@fedora13-intel64 ~]$ python
Python 2.6.4 (r264:75706, Apr  1 2010, 02:55:51) 
[GCC 4.4.3 20100226 (Red Hat 4.4.3-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import linecache
>>> sys.stdout.write(linecache.getline('/etc/passwd', 39))
kobakoba0723:x:501:501::/home/kobakoba0723:/bin/bash
>>> 
>>> for line_num, line_data in enumerate(open('/etc/passwd', 'rU')):
...     if line_num == 38:
...         sys.stdout.write(line_data)
...         break
... else:
...     sys.stdout.write('')
... 
kobakoba0723:x:501:501::/home/kobakoba0723:/bin/bash
>>> 
>>> sys.stdout.write(linecache.getline('/etc/passwd', 40))
>>> for line_num, line_data in enumerate(open('/etc/passwd', 'rU')):
...     if line_num == 39:
...         sys.stdout.write(line_data)
...         break
... else:
...     sys.stdout.write('')
... 
>>> 

ファイルの行数を数える(enumerate, timeit)

enumerate(sequence)を使うと、カウント(0スタート)とデータのタプルを返すので、
自分でカウンターの操作をしなくてもよい。

>>> print len(open('/etc/passwd', 'rU').readlines())
39
>>> count = -1
>>> for count, data in enumerate(open('/etc/passwd', 'rU')):
...     pass
... 
>>> count += 1
>>> print count
39
>>> 

timeitモジュールを使うと、実行時間を手軽に計測することが出来る。
クックブックではpopen()を使っていたが、どうも2.6ではpopenが廃止され、subporcessを使うことになっているそうな。
シェルプロセスを新しく起こすと遅いとは思ってたけど、2桁近く遅いとは。。。

>>> import timeit
>>> import shlex, subprocess
>>> def linecount_process():
...     return subprocess.Popen(["wc -l /etc/passwd"], shell=True, stdout=subprocess.PIPE).stdout.read().split()[0]
... 
>>> def linecount_len():
...     return len(open("/etc/passwd", "rU").readlines())
... 
>>> def linecount_enumerate():
...     count = -1
...     for count, data in enumerate(open("/etc/passwd", "rU")):
...         pass
...     return count + 1
... 
>>> 
>>> linecount_process()
'39'
>>> linecount_len()
39
>>> linecount_enumerate()
39
>>> 
>>> timeit.Timer("linecount_process()", "from __main__ import linecount_process").timeit(number=10)
0.10188198089599609
>>> timeit.Timer("linecount_len()", "from __main__ import linecount_len").timeit(number=10)
0.00042796134948730469
>>> timeit.Timer("linecount_enumerate()", "from __main__ import linecount_enumerate").timeit(number=10)
0.00047612190246582031
>>> 

正規表現モジュール(re)

以下の2つは同じ結果を返す。
その場でパターンを指定するか、あらかじめコンパイルしたパターンを使うか、が違うみたい。
なんでわざわざ2種類の方法があるのかなぁと思ってたけど、複数回使う場合を考えてのことらしい。

re_object=re.compile(pattern)
re_object.finditer(string)
re.finditer(pattern, string)

その他

入門GNU Emacsを読み終わったけど、CEDETが動かない理由は依然としてよくわからない。
Emacs Lispもさらっと眺めてみたけど、よくわからない状態。
python.elじゃなくて、python-mode.elを使ってるのが関係してるのかな。hookがうまく動かないとか*1
Cのソースでサンプル通りやってうまくいくか試してみようかなぁ。

Python クックブック 第2版

Python クックブック 第2版

*1:ってそんなことはないんだろうな、たくさんの人が使ってるメジャーモードだし。