将文件指针倒回上一行Python文件IO

将文件指针倒回上一行Python文件IO,python,file-io,Python,File Io,我正在读一个大的基因文件的格式 >GeneID ACTCTCTCTATATATATATAT\n GCTCTGCTTCTAGAGAGAGTG\n TCTATTTGTTTATATATCTTT\n >GeneID GCTCTGCTTCTAGAAATTCCC\n ACTCTGTATATATTTTCAAAA\n GCTCTGCTTCTAGAGAGAGTG\n 每个基因都以一个>开始,然后是一个唯一的ID。之后是该基因的核苷酸序列。 不幸的是,该文件的生成使得序列的每一行之间都有换行符 我需要

我正在读一个大的基因文件的格式

>GeneID
ACTCTCTCTATATATATATAT\n
GCTCTGCTTCTAGAGAGAGTG\n
TCTATTTGTTTATATATCTTT\n
>GeneID
GCTCTGCTTCTAGAAATTCCC\n
ACTCTGTATATATTTTCAAAA\n
GCTCTGCTTCTAGAGAGAGTG\n
每个基因都以一个>开始,然后是一个唯一的ID。之后是该基因的核苷酸序列。 不幸的是,该文件的生成使得序列的每一行之间都有换行符

我需要将每个序列作为一个连续字符串读取。因此,我一直在使用下一种方法(如下所示)

我发现我的脚本只拾取了文件中的一半基因,因为当在导致while循环失败的条件下调用next时,文件指针指向下一个基因ID,然后当for循环的下一次迭代执行时,它移动到下一个文件

有没有办法将文件指针倒回上一行,这样我的for循环就可以将其作为一个新基因捕获

我看到过类似的问题,但没有一个是关于我阅读文件的具体方式

  for line in file:
        #do stuff

读取fasta文件有更简单的方法,例如:

entries = []
for line in filer:
    if line.startswith('>'):
        entries.append((line.rstrip()[1:], []))
    else:
        entries[-1][1].append(line.rstrip())
这将为您提供一个元组列表。第一个元素是序列ID,第二个元素是序列列表

在此之后很容易加入序列:

entries = [(x, "".join(y)) for x,y in entries]

读取fasta文件有更简单的方法,例如:

entries = []
for line in filer:
    if line.startswith('>'):
        entries.append((line.rstrip()[1:], []))
    else:
        entries[-1][1].append(line.rstrip())
这将为您提供一个元组列表。第一个元素是序列ID,第二个元素是序列列表

在此之后很容易加入序列:

entries = [(x, "".join(y)) for x,y in entries]

我会使用生成器,而不是跳过行(有些东西告诉我这可以大大简化):

现在,您只需几行代码就可以安全地迭代整个过程:

with open('file.txt', 'r') as handle:
    for gene_id, nucleotides in parse_file(handle):
        print gene_id, nucleotides
还有

或使用
itertools
的更通用功能:

def grouper(line):
    return line.startswith('>') and line[1:]

def itersplit(it, pred):
    groups = (list(group) for key, group in itertools.groupby(it, pred))
    yield from zip(groups, groups)

def parse(file):
    for key, group in itersplit(file, grouper):
        yield key[0], ''.join(group)

我会使用生成器,而不是跳过行(有些东西告诉我这可以大大简化):

现在,您只需几行代码就可以安全地迭代整个过程:

with open('file.txt', 'r') as handle:
    for gene_id, nucleotides in parse_file(handle):
        print gene_id, nucleotides
还有

或使用
itertools
的更通用功能:

def grouper(line):
    return line.startswith('>') and line[1:]

def itersplit(it, pred):
    groups = (list(group) for key, group in itertools.groupby(it, pred))
    yield from zip(groups, groups)

def parse(file):
    for key, group in itersplit(file, grouper):
        yield key[0], ''.join(group)
有没有办法将文件指针倒回上一行,这样我的for循环就可以将其作为一个新基因捕获

在Python3中,不能。不能将文件迭代与文件指针上的显式操作混合使用

也许在Python 2中。但这只是偶然发生的,这就是为什么它在3.0中被禁止的原因,而且它不能保证在任何情况下都能正常工作。所以,你不应该这么做

更好的方法是询问如何倒带迭代器。答案是。您可以使用
tee
向前窥视。您可以将迭代器重新绑定到
链([推后值],迭代器)
。等等

但是,正如其他人所指出的,有一种更好的方法可以做到这一点。你真的不需要向前看或向后看,你只需要把事情分组。您也可以使用
itertools
来实现这一点,但在本例中,它非常简单,您不妨直接实现它,正如Blender所示

有没有办法将文件指针倒回上一行,这样我的for循环就可以将其作为一个新基因捕获

在Python3中,不能。不能将文件迭代与文件指针上的显式操作混合使用

也许在Python 2中。但这只是偶然发生的,这就是为什么它在3.0中被禁止的原因,而且它不能保证在任何情况下都能正常工作。所以,你不应该这么做

更好的方法是询问如何倒带迭代器。答案是。您可以使用
tee
向前窥视。您可以将迭代器重新绑定到
链([推后值],迭代器)
。等等


但是,正如其他人所指出的,有一种更好的方法可以做到这一点。你真的不需要向前看或向后看,你只需要把事情分组。您也可以使用
itertools
来实现这一点,但在本例中,它非常简单,您不妨直接实现它,正如Blender所示。

这里有另一个使用
re
mmap
的方法:

import mmap, re

with open(your_file) as fin:
    mm = mmap.mmap(fin.fileno(), 0, access=mmap.ACCESS_READ)
    for match in re.finditer('>([^\n]+)([^>]*)', mm, flags=re.DOTALL):
        print match.group(1), match.group(2).replace('\n', '')

#GeneID1 ACTCTCTCTATATATATATATGCTCTGCTTCTAGAGAGAGTGTCTATTTGTTTATATATCTTT
#GeneID2 GCTCTGCTTCTAGAAATTCCCACTCTGTATATATTTTCAAAAGCTCTGCTTCTAGAGAGAGTG

这样做可以将整个文件视为一个字符串,但会利用操作系统按需提供文件的一部分来完成正则表达式。由于它使用了
finditer
,我们也没有在内存中建立结果集。

这里有另一个使用
re
mmap
的方法:

import mmap, re

with open(your_file) as fin:
    mm = mmap.mmap(fin.fileno(), 0, access=mmap.ACCESS_READ)
    for match in re.finditer('>([^\n]+)([^>]*)', mm, flags=re.DOTALL):
        print match.group(1), match.group(2).replace('\n', '')

#GeneID1 ACTCTCTCTATATATATATATGCTCTGCTTCTAGAGAGAGTGTCTATTTGTTTATATATCTTT
#GeneID2 GCTCTGCTTCTAGAAATTCCCACTCTGTATATATTTTCAAAAGCTCTGCTTCTAGAGAGAGTG

这样做可以将整个文件视为一个字符串,但会利用操作系统按需提供文件的一部分来完成正则表达式。由于它使用了
finditer
,我们也没有在内存中建立结果集。

这不会错过最后一个条目吗?由于文件不是以
>
?@Blender开头的行结束的:首先将行上的迭代器分组为批上的迭代器,其中以
'>'
开头的行标记一个新的批,然后只处理每个批,显然可以简化文件。但我认为,对于新手来说,生成的代码可能更难理解,因此您已经编写的代码是说明这一想法的完美方式。@Blender:我将编写一个更通用的
itersplit
函数,它接受一个谓词和一个迭代器,每次谓词为真时,组上的迭代器都会被拆分。另外,我认为使用
takewhile
比使用
groupby
更简单。不过,我还是觉得你原来的版本更清晰了。@Blender:事实上,没关系;轻松使用
takewhile
需要在其
next
周围使用两个参数
iter
,这太傻了。但是你对
groupby
所做的只是(a)扔掉键,(b)列出值,以及(c)将值分组成对(因为键总是交替的),所以……这几乎是一个1行。请参阅我对您答案的编辑。@abarnert,只要在使用的Python版本中允许从中获得
收益。。。但是是的-比我的
mmap
re
方法好得多这不会错过最后一个条目吗?因为文件没有结束