2

次の Python スニペットを検討してください。

af=open("a",'r')
bf=open("b", 'w')

for i, line in enumerate(af):
    if i < K:
        bf.write(line)

ここで、Kisのケースを処理したいとNoneします。そのため、書き込みはファイルの最後まで続きます。私は現在やっています

if K is None:
    for i, line in enumerate(af):
        bf.write(line)
else:
    for i, line in enumerate(af):            
        bf.write(line)
        if i==K:
            break

コードを複製しているため、これは明らかにこれを処理する最善の方法ではありません。これを処理できる統合された方法はありますか? が存在しないif/break場合にのみコードが存在するようにするのが自然なことですが、これには Lisp マクロのようにオンザフライで構文を書くことが含まれますが、これは Python では実際にはできません。明確にするために、私は特定のケース (部分的に単純にするために選択した) については心配していません。KNone

更新: 人々が投稿した回答を読み、さらに実験を行った後、いくつかのコメントがあります。

上記のように、私は一般化できる一般的な手法を探していました.@Paulの答え、つまりtakewhilefromを使用するのiterroolsが最適だと思います。おまけとして、上記の単純な方法よりもはるかに高速です。理由はわかりません。itertools何度か見たことはありますが、あまり詳しくありません。私の観点からすると、これはFor The Win !の関数型プログラミングのケースです。(面白いことに、 の作成者は、 のitertoolsドロップについてフィードバックを求めたことがあります。 http://mail.python.org/pipermail/python-list/2007-December/522529.htmltakewhileで始まるスレッドを参照してください。) 上記の状況を単純化したところ、実際の状況はもう少し厄介です。ループ内の 2 つの異なるファイルに書き込んでいます。したがって、コードは次のようになります。

for i, line in enumerate(af):
    if i < K:
        bf.write(line)
        cf.write(line.split(',')[0].strip('"')+'\n')

私の投稿された例を考えると、@Jeff は合理的に、 is の場合はファイルをコピーすることを提案しましKNone。実際にはとにかくループしているので、そうするのはそれほど明確な選択ではありません。ただし、takewhileこの場合は簡単に一般化できます。ここでは言及していない別のユースケースもtakewhileあり、そこでも使用できてよかったです。2番目の例は次のようになります(逐語的に)

i=0
for line in takewhile(illuminacond, af):
    line_split=line.split(',')
    pid=line_split[1][0:3]
    out = line_split[1] + ',' + line_split[2] + ',' + line_split[3][1] + line_split[3][3] + ',' \
                        + line_split[15] + ',' + line_split[9] + ',' + line_split[10]
    if pid!='cnv' and pid!='hCV' and pid!='cnv':
        i = i+1
        of.write(out.strip('"')+'\n')
        tf.write(line)

ここで条件を使用できました

if K is None:
    illuminacond = lambda x: x.split(',')[0] != '[Controls]'
else:
    illuminacond = lambda x: x.split(',')[0] != '[Controls]' and i < K

@Paulの元の例ごと。iただし、コードは機能しますが、外側のスコープから取得しているという事実に完全に満足しているわけではありません。これを行うより良い方法はありますか?または、別の質問にする必要があるかもしれません。とにかく、私の質問に答えてくれたみんなに感謝します。いくつかの素晴らしい提案をしてくれた@Jeffへの名誉ある言及。

4

5 に答える 5

5
for i, line in enumerate(af):  
    if K is None or i < K:
        bf.write(line)
    else:
        break
于 2011-05-02T22:56:39.633 に答える
2

itertools.takewhile条件が適用され、条件が最初に失敗したときにループから抜け出します。

from itertools import takewhile

if K is None:
    condition = lambda x: True
else:
    condition = lambda x: x[0] < K

for i,line in takewhile(condition, enumerate(af)):
    bf.write(line)

K が None の場合、takewhile を停止させたくないので、条件関数は常に True を返す必要があります。しかし、K の数値が与えられた場合、タプルの 0 番目の要素が条件 >= K に渡されると、takewhile は停止します。

于 2011-05-02T22:59:57.273 に答える
1

K が何であれ、常に無限大より小さくなります。

if K is None:
    K = float('inf') # infinity

for i, line in enumerate(af):            
    bf.write(line)
    if i==K:
        break

または、設定K = -1は意味的には正しくありませんが、同様に機能します。理想的には af で K = max lines を設定しますが、データは安価に入手できないと思います。

于 2011-05-03T00:01:38.590 に答える
1

ループしなければならない場合は、これはどうですか?

from sys import maxint

limit = K or maxint
for i, line in enumerate(af):
    if i >= limit: break
    bf.write(line)

それともこれでも?

from itertools import islice
from sys import maxint

bf.writelines(islice(af, K or maxint))

その場合、なぜループするのKですNoneか?

from shutil import copyfile

名前 = 'a' bname = 'b' K が None の場合: copyfile(aname, bname) そうしないと: af = 開く (名前, 'r') bf = open(bname, 'w') i の場合、enumerate(af) の行: i < K の場合: bf.write(行)

于 2011-05-02T23:01:18.630 に答える
0

DRYの原則と最適化の間のトレードオフを受け入れる必要がある状況にあると思います。

私はDRYの原則に忠実であり続けることから始め、次のような関数で重複コードを削除しwrite_untilます...

def write_until(file_in,file_out,break_on)
    for i,line in enumerate(file_in)

        if break_on(i,line):
            break
        else:
            file_out.write(line)

af=open("a",'r')
bf=open("b", 'w')

if K is None:
    write_until(af,bf,lambda i,line: False)
else:
    write_until(af,bf,lambda i,line: i>K)

次に、実際にコードを使用して、本当に最適化を行う必要があるかどうかを確認します。チェックを削除することで、正直にどの程度のパフォーマンスの向上が見られますif Falseか?あなたが本当にその余分なスピードブーストを必要とするなら(私は疑います)、あなたはただいくつかのコードの重複に耐えなければならないでしょう。

于 2011-05-02T23:51:33.553 に答える