Python脚本无法提取.fa文件信息并拼接,请求排查解决
问题描述
编写了一段Python脚本,用于将多个.fa文件中的指定行提取并拼接至一个.txt文件,但自定义函数未能输出预期内容。具体需求如下:
- 文件夹内有数千个.fa文件,需提取每个文件中以
>开头的行 - 从每行中提取信息:基因名(
>后到空格前的内容)+ 物种名([]内的内容,无则为空),格式为基因名:物种名 - 每个文件的提取结果整合成一行,开头是文件名,后面跟所有提取的信息,最终写入.txt文件
文件夹结构
% ls EstimatedSpeciesTree.nwk HOG9998.fa concatenate_gene_list_HOG.py HOG9997.fa HOG9999.fa output
.fa文件示例
>BnaCnng71140D [BRANA] MTSSFKLSDLEEVTTNAEKIQNDLLKEILTLNAKTEYLRQFLHGSSDKTFFKKHVPVVSYEDMKPYIERVADGEPSEIIS GGPITKFLRRYSF >Cadbaweo98702.t [THATH] MTSSFKLSDLEEVTTNAEKIQNDLLKEILTLNAKTEYLRQFLHGSSDKTFFKKHVPVVSYEDMKPYIERVADGEPSEIIS GGPITKFLRRYSF
预期输出格式
HOG9997.fa BnaCnng71140D:BRANA Cadbaweo98702.t:THATH HOG9998.fa Bkjfnglks098:BSFFE dsgdrgg09769.t HOG9999.fa Dsdfdfgs1937:XDGBG Cadbaweo23425.t:THATH Dkkjewe098.t:THUGB # NOTE: the number of lines in each .fa file are uncertain. Also, some lines has [ ], but some lines has not.
当前代码
#!/usr/bin/env python3 import os import re import csv def concat_hogs(a_file): output = [] for row in a_file: # select the gene names in each HOG fasta file if row.startswith(">"): trans = row.partition(" ")[0].partition(">")[2] if row.partition(" ")[2].startswith("["): species = re.search(r"\[(.*?)\]", row).group(1) else: species = "" output.append(trans + ":" + species) return '\t'.join(output) folder = "/tmp/Fasta/" print("Concatenate names in " + folder) for file in os.listdir(folder): if file.endswith('.fa'): reader = csv.reader(file, delimiter="\t") print(file + concat_hogs(reader))
问题现象
当前输出仅显示文件名,自定义函数concat_hogs生成的内容为空。
问题排查与修复
错误原因分析
- 错误使用
csv.reader:csv.reader需要接收文件对象作为参数,而你传入的是文件名字符串,导致遍历的是文件名的单个字符,而非文件内容。同时.fa文件不是CSV格式,无需用csv模块处理。 - 未正确打开文件:
os.listdir返回的是文件名,需要拼接完整路径并打开文件才能读取内容。 - 输出分隔符不符预期:预期用空格分隔,但代码中用了
\t(制表符)拼接结果。 - 未处理行尾换行符:读取的行可能包含
\n,会影响字符串判断和处理。
修复后的代码
#!/usr/bin/env python3 import os import re def concat_hogs(file_path): output = [] # 打开文件并逐行读取,with语句自动管理文件关闭 with open(file_path, 'r') as f: for line in f: line = line.strip() # 去除首尾空白(包括换行符) if line.startswith(">"): # 提取基因名:>后到第一个空格前的内容 trans_part = line.partition(" ")[0] trans = trans_part.partition(">")[2] # 提取物种名:[]内的内容,无则为空 species_match = re.search(r"\[(.*?)\]", line) species = species_match.group(1) if species_match else "" output.append(f"{trans}:{species}") # 用空格拼接结果,符合预期格式 return ' '.join(output) folder = "/tmp/Fasta/" output_file_path = os.path.join(folder, "output.txt") print(f"Concatenate names in {folder}") # 打开输出文件准备写入 with open(output_file_path, 'w') as out_f: for file_name in os.listdir(folder): if file_name.endswith('.fa'): # 拼接完整文件路径,避免跨平台路径问题 full_path = os.path.join(folder, file_name) hog_content = concat_hogs(full_path) # 组合文件名和内容,写入文件 line_to_write = f"{file_name} {hog_content}\n" out_f.write(line_to_write) # 同时打印到控制台 print(line_to_write.strip()) print(f"Done! Output saved to {output_file_path}")
关键修改点说明
- 替换文件读取方式:去掉csv模块,改用原生
open()函数配合with语句读取文件,既简洁又能自动释放资源。 - 拼接完整路径:使用
os.path.join()处理路径,确保在Windows、Linux等不同系统下都能正确识别文件位置。 - 处理换行符:用
line.strip()清理每行的首尾空白,避免换行符干扰字符串判断逻辑。 - 简化物种名提取:直接通过正则匹配结果判断是否存在物种名,逻辑更清晰,避免冗余的字符串拆分判断。
- 符合输出格式:改用空格拼接提取的信息,同时将结果写入
output.txt文件,满足最终保存需求。
内容的提问来源于stack exchange,提问作者zzz
相关产品推荐
相关产品推荐

