Python-ファイルを読み取り、行を区切り文字で区切る最適な方法

file-io generator python
Python-ファイルを読み取り、行を区切り文字で区切る最適な方法

ファイルを読み取り、デリミタで行を分割する最良の方法は何ですか。 返されるデータはタプルのリストでなければなりません。

この方法は破られますか? これはより速く/より少ないメモリを使用して実行できますか?

def readfile(filepath, delim):
    with open(filepath, 'r') as f:
        return [tuple(line.split(delim)) for line in f]

  0  3


ベストアンサー

投稿されたコードは、ファイル全体を読み取り、すべてのファイルの内容をタプルに分割した単一のリストとしてメモリにファイルのコピーを作成します(1行につき1タプル)。 メモリの使用量を減らす方法を尋ねるので、必要なのはジェネレーター関数のみです。

def readfile(filepath, delim):
    with open(filepath, 'r') as f:
        for line in f:
            yield tuple(line.split(delim))

BUT! 大きな警告があります! readfileによって返されたタプルを1回だけ反復処理できます。

lines_as_tuples = readfile(mydata,','):

for linedata in lines_as_tuples:
    # do something

これは今のところ大丈夫で、ジェネレーターとリストは同じように見えます。 しかし、ファイルに多くの浮動小数点数が含まれていて、ファイルを反復処理するとそれらの数値の全体的な平均が計算されたとしましょう。 「#do something」コードを使用して、全体の合計と数を計算し、平均を計算できます。 しかし、今度は、各値の平均からの差を見つけるために、もう一度繰り返したいとしましょう。 別のforループを追加すると思うでしょう:

for linedata in lines_as_tuples:
    # do another thing
    # BUT - this loop never does anything because lines_as_tuples has been consumed!

BAM! これは、ジェネレータとリストの大きな違いです。 コードのこの時点で、ジェネレータは完全に消費されました-しかし、特別な例外は発生しません。forループは単に何もせず、静かに続行します!

多くの場合、返されるリストは1回だけ繰り返されます。その場合、readfileからジェネレーターへの変換は問題ありません。 しかし、複数回アクセスするより永続的なリストが必要な場合は、ジェネレーターを1回だけ反復できるため、ジェネレーターを使用するだけで問題が発生します。

私のおすすめ? readlinesをジェネレーターにします。これにより、独自の世界観では、ファイルの各増分ビットが生成され、メモリ効率が良くなります。 データの保持の負担を呼び出し元に置きます-呼び出し元が返されたデータを複数回参照する必要がある場合、呼び出し元はジェネレータから独自のリストを簡単に作成できます
– Pythonで `list(readfile( ‘file.dat’、 ‘、’))`を使用して簡単に実行できます。

14


リストの代わりにジェネレーターを使用し、タプルの代わりにリストを使用すると、メモリー使用量を削減できるため、一度にファイル全体をメモリーに読み込む必要はありません。

def readfile(path, delim):
    return (ln.split(delim) for ln in open(f, 'r'))

ただし、ファイルを閉じるにはガベージコレクターに依存する必要があります。 タプルを返すことに関しては、リストがごくわずかな高速であるため、必要でない場合は行わないでください。タプルの構築にはわずかなコストがかかり、(重要な)行は概念的にリストである可変サイズのシーケンスに分割されます。

速度は、C / Cythonレベルに下げることによってのみ改善できると思います。 `str.split`はCで書かれているので、打ち負かすのが難しく、リストの内包表記はPythonの最速のループ構造です。

さらに重要なことに、これは非常に明確でPythonicコードです。 ジェネレータービット以外は最適化を試みません。

3


タイトルとURLをコピーしました