Skip to main content
 首页 » 编程设计

python之循环打开和关闭文件

2025年05月04日13虾米姐

假设我有一个包含数万个条目的列表,我想将它们写入文件。如果列表中的项目符合某些条件,我想关闭当前文件并开始一个新文件。

我有几个问题,我认为它们源于我想根据该文件中的第一个条目命名文件。此外,开始新文件的信号基于条目是否具有与前一个相同的字段。因此,例如假设我有列表:

l = [('name1', 10), ('name1', 30), ('name2', 5), ('name2', 7), ('name2', 3), ('name3', 10)] 

我想以 3 个文件结束,name1.txt 应该包含 10 和 30,name2.txt 应该有 5、7 和 3,name3.txt 应该有 10 。该列表已经按第一个元素排序,所以我需要做的就是检查第一个元素是否与前一个元素相同,如果不相同,则启动一个新文件。

一开始我试过:

name = None 
for entry in l: 
    if entry[0] != name: 
        out_file.close() 
        name = entry[0] 
        out_file = open("{}.txt".format(name)) 
        out_file.write("{}\n".format(entry[1])) 
    else: 
        out_file.write("{}\n".format(entry[1])) 
 
out_file.close() 

据我所知,这有几个问题。首先,第一次通过循环时,没有要关闭的 out_file。其次,我无法关闭最后创建的 out_file,因为它是在循环内定义的。下面解决了第一个问题,但看起来很笨拙:

for entry in l: 
    if name: 
        if entry[0] != name: 
            out_file.close() 
            name = entry[0] 
            out_file = open("{}.txt".format(name)) 
            out_file.write("{}\n".format(entry[1])) 
        else: 
            out_file.write("{}\n".format(entry[1])) 
    else: 
        name = entry[0] 
        out_file = open("{}.txt".format(name)) 
        out_file.write("{}\n".format(entry[1])) 
 
out_file.close() 

有更好的方法吗?

而且,这似乎不能解决关闭最后一个文件的问题,尽管这段代码运行良好——我是不是误解了 out_file 的范围?我认为它会被限制在 for 循环内。

编辑:我应该提一下,我的数据比这里显示的要复杂得多......它实际上不在列表中,它是一个 SeqRecord from BioPython

编辑 2:好的,我以为我正在简化以避免分心。显然产生了相反的效果 - mea culpa。以下是上面第二个代码块的等价物:

from re import sub 
from Bio import SeqIO 
 
def gbk_to_faa(some_genbank): 
    source = None 
    for record in SeqIO.parse(some_genbank, 'gb'): 
        if source: 
            if record.annotations['source'] != source: 
                out_file.close() 
                source = sub(r'\W+', "_", sub(r'\W$', "", record.annotations['source'])) 
                out_file = open("{}.faa".format(source), "a+") 
                write_all_record(out_file, record) 
            else: 
                write_all_record(out_file, record) 
        else: 
            source = sub(r'\W+', "_", sub(r'\W$', "", record.annotations['source'])) 
            out_file = open("{}.faa".format(source), "a+") 
            write_all_record(out_file, record) 
 
    out_file.close() 
 
 
def write_all_record(file_handle, gbk_record): 
    # Does more stuff, I don't think this is important 
    # If it is, it's in this gist: https://gist.github.com/kescobo/49ab9f4b08d8a2691a40 

请您参考如下方法:

使用Python提供的工具更容易:

from itertools import groupby 
from operator import itemgetter 
 
items = [ 
    ('name1', 10), ('name1', 30), 
    ('name2', 5), ('name2', 7), ('name2', 3), 
    ('name3', 10) 
] 
 
for name, rows in groupby(items, itemgetter(0)): 
    with open(name + ".txt", "w") as outf: 
        outf.write("\n".join(str(row[1]) for row in rows)) 

编辑:以匹配更新的问题,这里是更新的解决方案;-)

for name, records in groupby(SeqIO.parse(some_genbank, 'gb'), lambda record:record.annotations['source']): 
    with open(name + ".faa", "w+") as outf: 
        for record in records: 
            write_all_record(outf, record)