如何加速Python中的FASTA文件子采样程序?
Let's tackle your two main issues one by one—performance bottlenecks and the terminal input hang-up.
1. Performance Optimization: Why .pop() Is Slow & How to Fix It
You're right to suspect .pop(a) as the bottleneck. Here's why:
- When you call
list.pop(index)whereindexisn't the last element, Python has to shift all elements after the index left by one position to fill the gap. This is an O(n) operation each time. - If you're extracting 2 million sequences, that's 2 million O(n) operations—this adds up exponentially and kills performance.
Better Approach: Generate Unique Random Indices First
Instead of modifying your lists repeatedly with .pop(), use random.sample() to generate all your target indices in one go. This function is optimized to pick k unique elements from a sequence without replacement, and it's way faster than looping randint() + .pop().
Additional optimizations:
- Use context managers (
withstatements) for file handling: they automatically close files for you, avoiding resource leaks and making code cleaner. - Batch write to the output file instead of printing line-by-line: I/O operations are slow, so collecting all lines first and writing once reduces overhead drastically.
Optimized Code Snippet
#!/usr/bin/env python3 import random import sys def main(): # Get number of sequences to extract num = int(input("Enter number of random sequences to select:\n")) # Use context managers for safe, automatic file handling with open(sys.argv[1], "r") as infile, open(sys.argv[2], "w") as outfile: fNames = [] fSeqs = [] # Parse FASTA into lists (your original fast parsing logic stays!) for line in infile: stripped_line = line.rstrip() if stripped_line.startswith(">"): fNames.append(stripped_line) else: fSeqs.append(stripped_line) total_seqs = len(fNames) print(f"There are {total_seqs} sequences in the input file") # Validate input to avoid errors if num > total_seqs: print(f"Warning: Requested {num} sequences, but only {total_seqs} exist. Extracting all.") num = total_seqs # Generate all unique random indices in one optimized step random_indices = random.sample(range(total_seqs), num) # Prepare all output lines at once output_lines = [] for idx in random_indices: output_lines.append(fNames[idx]) output_lines.append(fSeqs[idx]) # Write everything to file in a single operation outfile.write("\n".join(output_lines) + "\n") print("Done.") if __name__ == "__main__": main()
2. Fixing the Terminal Input Hang-Up
The issue with your terminal not returning to normal input after input("Done.") happens because:
- The
input()call waits for user input, but in some terminal environments (especially after handling large outputs), the terminal's input buffer or settings can get corrupted, preventing it from returning to an interactive state. - In rare cases, if the script runs in a non-interactive shell,
input()can cause unexpected hangs.
Simple Fix
Just replace input("Done.") with print("Done."). This way, the script prints the completion message and exits immediately, returning full control to your terminal without waiting for extra input.
If you really want to wait for user confirmation before exiting (though it's usually unnecessary), use a more robust alternative:
import sys print("Done. Press Enter to exit...") sys.stdin.readline()
But in most cases, print("Done.") is the cleanest solution.
内容的提问来源于stack exchange,提问作者Néstor

