Python 3.x-如何有效地将对象数组拆分为较小的批处理文件?
作者:互联网
我对Python相当陌生,我试图将一个文本文件(其中条目由两行组成)拆分为max. 400个对象.
我正在使用的数据是FASTA格式(带有标头的纯文本,用于生物信息学)的数千个序列,其中的条目如下所示:
>HORVU6Hr1G000325.5
PIPPPASHFHPHHQNPSAATQPLCAAMAPAAKKPPLKSSSSHNSAAGDAA
>HORVU6Hr1G000326.1
MVKFTAEELRGIMDKKNNIRNMSVIAHVD
…
在Biopython中,有一个解析器SeqIO.parse,它允许将它们作为由ID和字符串组成的对象数组进行访问,我需要在代码的后续部分中使用它们,并且由于我需要提高内存效率,因此为了避免不必要的次数读取/解析源文件.
在Biopython手册中,有一种推荐的方式可以通过生成器来实现,我正在使用:https://biopython.org/wiki/Split_large_file
但是,我使用的是Python 3.7,而其中的代码在Python 2.x中,因此肯定需要进行一些更改.我已经改变了
entry = iterator.next()
进入
entry = next(iterator)
但我不确定这是否就是我需要改变的.
这是代码:
def batch_iterator(iterator, batch_size=400):
"""Returns lists of length batch_size."""
entry = True # Make sure we loop once
while entry:
batch = []
while len(batch) < batch_size:
try:
entry = next(iterator)
except StopIteration:
entry = None
if entry is None:
# End of file
break
batch.append(entry)
if batch:
yield batch
while True:
bsequence = input("Please enter the full path to your FASTA file(e.g. c:\\folder1\\folder2\\protein.fasta):\n")
try:
fastafile = open(bsequence)
break
except:
print("File not found!\n")
record_iter = SeqIO.parse(fastafile,"fasta")
num = 0
for line in fastafile:
if line.startswith(">"):
num += 1
print("num=%i" % (num,))
if num > 400:
print("The specified file contains %i sequences. It's recommended to split the FASTA file into batches of max. 400 sequences.\n" % (num,))
while True:
decision = input("Do you wish to create batch files? (Original file will not be overwritten)\n(Y/N):")
if (decision == 'Y' or 'y'):
for i, batch in enumerate(batch_iterator(record_iter, 400), 1):
filename = "group_%i.fasta" % (i + 1)
with open(filename, "w") as handle:
count = SeqIO.write(batch, handle, "fasta")
print("Wrote %i records to %s" % (count, filename))
break
elif (decision == 'N' or 'n'):
break
else:
print('Invalid input\n')
...next part of the code
当我运行此命令时,在Y / N提示符后,即使我键入Y,该程序也将跳过代码的下一部分而不创建任何新文件.调试器显示以下内容:
Do you wish to create batch files? (Original file will not be overwritten)
(Y/N):Y
Traceback (most recent call last):
File "\Biopython\mainscript.py", line 32, in batch_iterator
entry = next(iterator)
StopIteration
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1569, in _trace
return self._trace_and_catch(frame, event, arg)
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1611, in _trace_and_catch
frame.f_back, event, marker_function_args, node
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1656, in _handle_progress_event
self._save_current_state(frame, event, args, node)
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1738, in _save_current_state
exception_info = self._export_exception_info()
File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\backend.py", line 1371, in _export_exception_info
"affected_frame_ids": exc[1]._affected_frame_ids_,
AttributeError: 'StopIteration' object has no attribute '_affected_frame_ids_'
我忽略的Python 2.x和3.x之间有什么区别吗?问题在其他地方吗?这种方法完全错误吗?提前致谢!
解决方法:
由于您省略了一部分代码,因此我无法检查整个代码,但在这里我会看到两处错误的内容:
num = 0
for line in fastafile:
if line.startswith(">"):
num += 1
这些行耗尽了您的文件对象fastafile.完全删除这些行(并记住要修复下面的缩进,如果num> 400:请取消,等等).
if (decision == 'Y' or 'y'):
这并没有按照您的想法做.将其更改为if决策(‘Y’,’y’):或if Decision.lower()==’y’:.您在下面的if(decision ==’N’或’n’):行中重复此模式,因此也进行更改.
进行更改,然后尝试再次运行代码.
说明
第一个问题:在Python中,文件对象(即open(‘filename.txt’,’r’)返回的内容)是一个生成器,这意味着它只能被迭代一次.乍一看这似乎有些怪异,但这就是使用生成器的全部意义所在.生成器作为文件对象允许文件逐行循环,而不必一次加载整个文件内容-生成器仅跟踪下一行.
缺点是它们不能向后移动,因此当您在fastafile块中编写for行时,将耗尽生成器.当您稍后尝试调用batch_iterator(record_iter,400)时,record_iter中的生成器已经用尽,这就是为什么您以后会遇到错误的原因-如果没有任何要解析的内容,batch_iterator无法解析fasta序列.
第二个问题:对于带有布尔运算符的条件,例如if(decision ==’Y’或’y’):, Python将始终分别评估双方.因此,Python实际上会查看(bool(decision ==’Y’)还是bool(‘y’)):.
由于bool(‘y’)的计算结果为True(就像任何非空字符串一样),因此您的表达式变为if(bool(decision ==’Y’)或True):,这显然总是对的.
使用我建议的一种方法,以便将变量与条件中的多个值进行比较.
标签:biopython,next,python-3-x,generator,python 来源: https://codeday.me/bug/20191210/2104956.html