2013-07-16 70 views
0

我讀通過量的格式倒帶文件指針到當前行的Python文件IO

>GeneID 
ACTCTCTCTATATATATATAT\n 
GCTCTGCTTCTAGAGAGAGTG\n 
TCTATTTGTTTATATATCTTT\n 
>GeneID 
GCTCTGCTTCTAGAAATTCCC\n 
ACTCTGTATATATTTTCAAAA\n 
GCTCTGCTTCTAGAGAGAGTG\n 

每個基因啓動與一>那麼唯一ID的大型基因文件。來到該基因的核苷酸行後。 不幸的是,這個文件是這樣生成的,因此每一行序列之間都有換行符。

我需要讀取每個序列作爲一個連續的字符串。所以,我一直在使用下一個方法(如下所示)。

for line in filer: 
    if line.startswith(">"): 

     # Find Sequences 
     seq_seg = next(filer) 
     seq = "" 

     # Concatenate lines until find next gene 
     while not (seq_seg.startswith(">")): 
      seq += seq_seg.strip() # Get rid of '\n' 
      seq_seg = next(filer) 

我覺得,因爲在下次拜訪,使while循環失敗的情況我的腳本只撿基因的一半的文件,文件指針指向下一個基因ID,然後當for循環的下一次迭代執行時,它將移動到下一個文件。

有沒有辦法將文件指針倒回到前一行,所以我的for循環捕捉到一個新的基因?

我見過類似的問題,但他們沒有解決,我通過文件與

for line in file: 
     #do stuff 
+0

你真的真的不想在迭代器上調用'next',而已經循環遍歷同一個迭代器,除非你想完全按照你的方式完成迭代。 – abarnert

回答

3

我會用,而不是通過線跳過發電機(東西告訴我,這樣可以大大簡化):

def parse_file(file): 
    id = '' 
    gene = '' 

    for line in file: 
     if line.startswith('>'): 
      if gene: 
       yield id, gene 

      id = line[1:] 
      gene = '' 
     else: 
      gene += line.strip() 
    else: 
     yield id, gene # Final gene 

現在,你可以用幾行代碼安全地迭代整個事情:

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

這裏有也pyfasta

或用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) 
+0

這不會錯過最後一個條目嗎?由於該文件不以'>'開頭的行結束? – GWW

+0

@GWW:是的,謝謝。 – Blender

+0

@Blender:通過首先將遍歷行的迭代器分組到批處理迭代器,其中以'>'開始的行標記爲新行,然後處理每個批處理,這絕對可以簡化。但是我認爲最終的代碼對於新手來說很難理解,所以你已經寫過的代碼是闡述這個想法的完美方式。 – abarnert

0

閱讀有更容易的方式來讀取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] 
1

有沒有辦法倒帶的文件指針前行,所以我的for循環捕捉,作爲一個新的基因?

在Python 3中,沒有。您不能將文件迭代與文件指針上的顯式操作混合使用。

在Python 2中,也許。但這只是偶然發生的,這就是爲什麼它在3.0版本中被禁止的原因,並不能保證在任何情況下都能正常工作。所以,你不應該這樣做。

更好的方法是詢問如何倒帶迭代器。答案是itertools。你可以通過使用tee來窺視。您可以將迭代器重新綁定到chain([pushed_back_value], iterator)。等等。

但是,正如其他人指出的那樣,還有更好的方法來做到這一點。你不需要向前看在這裏尋找,你只需要分組的東西。您也可以用itertools來做到這一點,但在這種情況下,您可能會明確地做到這一點,就像Blender所顯示的那樣。

1

下面是一個使用remmap另一種方法:

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我們也沒有在內存中建立一個結果集。