python作为脚本语言,他比shell的表达能力更强,比c语言更容易使用,用作解析文件是再好不过的。
针对一个fasta文件,比如下面这个这个文件,虽然很短,但包含了fasta中所有的情况,即seq序列有放在一行的情况,也有放在多行的情况(对fasta文件不熟悉的同学,可以去复习Fasta和Fastq文件)。
>seq1 AGCTAGCT >seq2 AAAAAAAAAA >seq3 AGCTGGGGAAAAAA AAAAA
这里先给出python程序(假定上面的fasta文件内容存在test.fa
文件中)
def parse_fasta(fasta_path): f = open(fasta_path, 'r') seqs = {} # 用一个字典去存储解析出来的序列 seq_name = None for line in f: # 这里没有直接用read()方法,是为了避免出现文件过大,难以一次性读入内存 if not line:break if line.startswith('>'): # 以>开头,说明是含有序列名的行 seq_name = line[1:].strip('\n') if seq_name not in seqs: seqs[seq_name] = '' else: seqs[seq_name] += line.strip('\n') return seqs
通过循环结构一行一行的解析文件,将序列名和序列本身一一对应起来。但是需要使用一个字典来存储解析得来的序列,在序列内容非常大时,会对内存造成一定压力。下面我们来使用生成器来改造我们的代码。
def parse_fasta(fasta_path): f = open(fasta_path, 'r') seq_name = None seq = None for line in f: # 这里没有直接用read()方法,是为了避免出现文件过大,难以一次性读入内存 if not line:break if line.startswith('>'): # 以>开头,说明是含有序列名的行 seq_name = line[1:].strip('\n') if seq: yield seq_name,seq seq = '' else: seq += line.strip('\n') yield seq_name,seq
在生成器版本中,我们将字典换成了一个变量,这样程序只需要保存一个变量,这样就减少了内存压力。