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

问题描述 投票:3回答:1

我是Python的新手,我正在尝试将一个文本文件拆分成两个行,其中包含最多两个行。 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(迭代器)

但我不确定这是否需要改变。

这是代码:

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之间有什么区别吗?问题出在别处吗?这种做法完全错了吗?提前致谢!

python python-3.x generator next biopython
1个回答
2
投票

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

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'):这行重复这个模式,所以也改变它。

进行更改并尝试再次运行代码。

说明

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

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

第二个问题:对于具有布尔运算符(如if (decision == 'Y' or 'y'):)的条件,Python将始终单独评估双方。所以Python实际上看到了if (bool(decision == 'Y') or bool('y')):

由于bool('y')评估为True(就像任何非空字符串一样),你的表达式变成了if (bool(decision == 'Y') or True):,这显然总是正确的。

使用我建议的方法之一,以便将变量与条件中的多个值进行比较。

© www.soinside.com 2019 - 2024. All rights reserved.