循环打开和关闭文件
Opening and closing files in a loop
假设我有一个包含数万个条目的列表,我想将它们写入文件。如果列表中的项目符合某些条件,我想关闭当前文件并开始一个新文件。
我有几个问题,我认为它们源于我想根据该文件中的第一个条目命名文件。此外,开始新文件的信号基于条目是否具有与前一个相同的字段。因此,例如假设我有列表:
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
如果你不介意使用pandas
,你可以这样处理:
import pandas as pd
df = pd.DataFrame(l)
df.columns = ['name', 'value']
df.groupby('name').apply(lambda x: x.to_csv('{}.txt'.format(x['name'].iloc[0]), index=False, header=False))
获取三个名为 name1.txt
等的文本文件,如下所示:
name1,10
name1,30
在不影响代码的情况下,为什么不在关闭前检查 out_file
变量是否存在?
out_file=None
... #Some code
if out_file:
out_file.close()
您也可以为此使用 try/except
。
或者甚至可能 class(虽然矫枉过正):
class f_temp():
name = None
def close(self):
pass
out_file = f_temp()
for entry in l:
if entry[0] != out_file.name:
...
现在多读一点,为什么不按文件名对数据排序,一次只打开一个文件?
您也可以为此使用字典:
file_dict =dict()
for filename, value in l:
if filename not in file_dict():
file_dict[filename] = open("{}.txt".format(filename))
file_dict[filename].write("{}\n".format(entry[1]))
for item in file_dict.items():
item.close()
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)
假设我有一个包含数万个条目的列表,我想将它们写入文件。如果列表中的项目符合某些条件,我想关闭当前文件并开始一个新文件。
我有几个问题,我认为它们源于我想根据该文件中的第一个条目命名文件。此外,开始新文件的信号基于条目是否具有与前一个相同的字段。因此,例如假设我有列表:
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
如果你不介意使用pandas
,你可以这样处理:
import pandas as pd
df = pd.DataFrame(l)
df.columns = ['name', 'value']
df.groupby('name').apply(lambda x: x.to_csv('{}.txt'.format(x['name'].iloc[0]), index=False, header=False))
获取三个名为 name1.txt
等的文本文件,如下所示:
name1,10
name1,30
在不影响代码的情况下,为什么不在关闭前检查 out_file
变量是否存在?
out_file=None
... #Some code
if out_file:
out_file.close()
您也可以为此使用 try/except
。
或者甚至可能 class(虽然矫枉过正):
class f_temp():
name = None
def close(self):
pass
out_file = f_temp()
for entry in l:
if entry[0] != out_file.name:
...
现在多读一点,为什么不按文件名对数据排序,一次只打开一个文件?
您也可以为此使用字典:
file_dict =dict()
for filename, value in l:
if filename not in file_dict():
file_dict[filename] = open("{}.txt".format(filename))
file_dict[filename].write("{}\n".format(entry[1]))
for item in file_dict.items():
item.close()
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)