Python 3.x -如何有效地将对象数组拆分为较小的批处理文件?

a0zr77ik  于 2023-06-04  发布在  Python
关注(0)|答案(1)|浏览(305)

我对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和Python 3.x之间有什么我忽略的区别吗?问题出在别的地方吗?这种做法是否完全错误?先谢谢你了!

jdzmm42g

jdzmm42g1#

我不能检查你的整个代码,因为你已经省略了它的一部分,但我可以看到两个错误的事情在这里:

num = 0
for line in fastafile:
    if line.startswith(">"):
        num += 1

这些行正在耗尽文件对象fastafile。完全删除这些行(并记住修复下面的缩进,删除if num > 400:检查等)。

if (decision == 'Y' or 'y'):

这不是你想的那样将其更改为if decision in ('Y', 'y'):if decision.lower() == 'y':。在下面的if (decision == 'N' or 'n'):行中重复这个模式,所以也要修改它。
进行更改并尝试再次运行代码。

说明

第1期:在Python中,文件对象(即open('filename.txt', 'r')返回的)是一个生成器,这意味着它只能迭代一次。这可能看起来有点奇怪,但这就是使用生成器的全部意义。作为文件对象的生成器允许文件逐行循环,而不必一次加载整个文件内容-生成器只需跟踪下一行。

另一方面,它们不能倒退,所以当你写for line in fastafile块时,你耗尽了生成器。当您稍后尝试调用batch_iterator(record_iter, 400)时,record_iter中的生成器已经耗尽,这就是为什么您稍后会遇到错误-如果没有任何东西可以解析,则batch_iterator无法解析fasta序列。

第2期:对于带有布尔运算符的条件,例如if (decision == 'Y' or 'y'):,Python总是分别计算两边。所以Python实际上看到的是if (bool(decision == 'Y') or bool('y')):

由于bool('y')的计算结果为True(就像任何非空字符串一样),因此表达式变为if (bool(decision == 'Y') or True):,这显然总是为真。
使用我建议的方法之一,以便将变量与条件中的多个值进行比较。

相关问题