在Python代码中避免代码重复

2 投票
5 回答
2624 浏览
提问于 2025-04-16 16:51

考虑以下这段Python代码:

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

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

现在,假设我想处理一个情况,就是当 KNone 的时候,写入操作可以继续到文件的末尾。现在我正在这样做:

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

显然,这不是处理这个问题的最佳方法,因为我在重复代码。有没有更好的方法来处理这个问题呢?理想的情况是,只有在 K 不是 None 的时候,才有 if/break 这段代码,但这就涉及到像Lisp宏那样动态写语法,而Python其实做不到这一点。为了明确,我并不太关心这个特定的情况(我选择这个例子部分是因为它简单),我更想了解一些我可能不熟悉的通用技巧。

更新:在阅读了大家的回答并进行了一些实验后,我有了一些新的想法。

如上所述,我在寻找可以推广的通用技巧,我认为 @Paul 的回答,使用 takewhile 来自 itertools,是最合适的。作为额外的好处,它的速度也比我上面提到的简单方法快很多;我不太清楚为什么。我对 itertools 不是很熟悉,虽然我看过几次。从我的角度来看,这就是函数式编程的胜利!(有趣的是,itertools 的作者曾经询问过是否应该去掉 takewhile。可以查看这个讨论 http://mail.python.org/pipermail/python-list/2007-December/522529.html。)我上面简化了我的情况,实际上情况要复杂一些——我在循环中写入两个不同的文件。所以代码看起来更像是:

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

根据我发布的例子,@Jeff 合理地建议,当 KNone 的时候,我可以直接复制文件。因为实际上我无论如何都在循环,所以这样做并不是一个明确的选择。不过,takewhile 在这个情况下也能轻松推广。我还有一个没有提到的用例,也能在那儿使用 takewhile,这让我觉得很不错。第二个例子看起来是(逐字)

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,他提出了一些很好的建议。

相关问题:

5 个回答

1
from shutil import copyfile

aname = 'a' bname = 'b' if K is None: copyfile(aname, bname) else: af = open(aname, 'r') bf = open(bname, 'w') for i, line in enumerate(af): if i < K: bf.write(line)

如果你一定要使用循环,那这样做怎么样?

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))

如果KNone,那为什么还要循环呢?

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

当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。

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,说明你希望这个功能一直运行下去,所以条件函数应该总是返回 True。可是如果你给了一个数字 K,当传给条件的元组的第一个元素大于等于 K 时,takewhile 就会停止。

撰写回答