linecache – テキストファイルを効率的に読み込む

目的:ファイルまたはインポートされた Python モジュールからテキストの行を取り出して、同じファイルから効率的に多くの行を読み込むキャッシュを保持する
利用できるバージョン:1.4

linecache モジュールは、Python のソースファイルを扱うときに Python 標準ライブラリ全体で広く使用されています。そのキャッシュの実装は、メモリ内のディクショナリへ解析した行単位で、単純にファイルのコンテンツを保持します。その API はリストにインデクシングすることで要求された行を返します。これにより、ファイルを(何回も)読み込んでから、必要な部分を見つけるために行を解析する時間を節約します。特にエラーリポートのためにトレースバック情報を生成するようなときに、同じファイルから複数行を探すと便利です。

テストデータ

サンプルの入力として、ロレイムイプサム生成機で作成したテキストを使用します。

import os
import tempfile

lorem = '''Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vivamus eget elit. In posuere mi non risus. Mauris id quam posuere
lectus sollicitudin varius. Praesent at mi. Nunc eu velit. Sed augue
massa, fermentum id, nonummy a, nonummy sit amet, ligula. Curabitur
eros pede, egestas at, ultricies ac, pellentesque eu, tellus. 

Sed sed odio sed mi luctus mollis. Integer et nulla ac augue convallis
accumsan. Ut felis. Donec lectus sapien, elementum nec, condimentum ac,
interdum non, tellus. Aenean viverra, mauris vehicula semper porttitor,
ipsum odio consectetuer lorem, ac imperdiet eros odio a sapien. Nulla
mauris tellus, aliquam non, egestas a, nonummy et, erat. Vivamus
sagittis porttitor eros.'''

def make_tempfile():
    fd, temp_file_name = tempfile.mkstemp()
    os.close(fd)
    f = open(temp_file_name, 'wt')
    try:
        f.write(lorem)
    finally:
        f.close()
    return temp_file_name

def cleanup(filename):
    os.unlink(filename)

特定の行を読み込む

ファイルから5行目を読み込むには1行のコードで済みます。 linecache モジュールの行番号は 1 から始まりますが、もしそのオリジナルの文字列を split() するなら、その配列に 0 からインデクシングされることに注意してください。さらにキャッシュから返される値から行末の改行を取り除く必要もあります。

import linecache
from linecache_data import *

filename = make_tempfile()

# ソースとキャッシュから同じ行を取り出す
# (linecache は 1 から始まるのに注意してください)
print 'SOURCE: ', lorem.split('\n')[4]
print 'CACHE : ', linecache.getline(filename, 5).rstrip()

cleanup(filename)
$ python linecache_getline.py
SOURCE:  eros pede, egestas at, ultricies ac, pellentesque eu, tellus.
CACHE :  eros pede, egestas at, ultricies ac, pellentesque eu, tellus.

空行の扱い

次に空行だったときに何が起こるかを見てみましょう。

import linecache
from linecache_data import *

filename = make_tempfile()

# 空行に改行が含まれる
print '\nBLANK : "%s"' % linecache.getline(filename, 6)

cleanup(filename)
$ python linecache_empty_line.py

BLANK : "
"

エラー制御

要求された行がファイルの有効な行範囲になかった場合、 linecache は空行を返します。

import linecache
from linecache_data import *

filename = make_tempfile()

# キャッシュはいつも文字列を返します
# 存在しない行は空行で表します
not_there = linecache.getline(filename, 500)
print '\nNOT THERE: "%s" includes %d characters' %  (not_there, len(not_there))

cleanup(filename)
$ python linecache_out_of_range.py

NOT THERE: "" includes 0 characters

そのファイルが存在していなかったとしても linecache モジュールは決して例外を発生させません。

import linecache

# linecache がファイルを見つけられなくてもエラーが隠される
no_such_file = linecache.getline('this_file_does_not_exist.txt', 1)
print '\nNO FILE: ', no_such_file
$ python linecache_missing_file.py

NO FILE:

Python のソースファイル

linecache はトレースバック情報を生成するときによく使用されるので、目玉機能の1つは、モジュールの名前を指定して import path から Python のソースモジュールを見つける機能です。 linecache のキャッシュ生成コードは、直接的にそのファイルを見つけられなかったときに sys.path からそのモジュールを探します。

import linecache

# sys.path を検索して linecache モジュールを探す
module_line = linecache.getline('linecache.py', 3)
print '\nMODULE : ', module_line
$ python linecache_path_search.py

MODULE :  This is intended to read lines from modules imported -- hence if a filename

See also

linecache
本モジュールの標準ライブラリドキュメント
http://www.ipsum.com/
ロレイムイプサム生成機
ファイルアクセス
ファイルと連携するその他のツール
Bookmark and Share