函数中的 Subprocess.call() 不会暂停调用该函数的脚本

问题描述

我查看并找到了解决方案,尝试了它们并得到了相同的结果。我尝试使用 Popen.wait()run()call()。正如其他用户所建议的,我也尝试将命令作为字符串列表传递。没用。子进程调用不会出错,所以这不是问题。

功能如下:

def blast(file):
    command = f'blastn -query {output_path}fasta_files/{file} -db {db_path} -max_hsps 1 -max_target_seqs 40 -num_threads 4 -evalue 1e-5 ' \
              f'-out {output_path}blast/{file[:-2]}txt -outfmt "6 qseqid sseqid pident staxids sskingdoms qstart qend ' \
              f'qlen length sstart send slen evalue mismatch gapopen bitscore stitle"'
    subprocess.Popen(command,stdout=subprocess.PIPE,shell=True).wait()

这是对函数调用

import blastn
from process_blast_output import *
from remove_false_sequences import *
import os

directory = '/some/path/'


if __name__ == '__main__':
    for file in os.listdir(directory + 'fasta_files'):
        if 'btcaA1_trimmed' in file:
            blastn.blast(f'{file}') # That's where the function is called
            dataframe = get_dataframe(directory + f'blast/{file[:-2]}txt')
            dataframe = get_taxonomic_data(dataframe)
            delete_false_hits(fasta_to_dictionary(dataframe),directory + f'fasta_files/{file[:-2]}fa')

我还尝试传递一个列表,而不是传递一个字符串:

subprocess.Popen(['blastn','-query',f'{output_path}fasta_files/{file}','-db',f'{db_path}','-max_hsps','1','-max_target_seqs','40','-num_threads','4','-evalue','1e-5','-out',f'{output_path}blast/{file[:-2]}txt','-outfmt',"6 qseqid sseqid pident staxids sskingdoms "
                                                                   "qstart qend qlen length sstart send slen evalue"
                                                                   " mismatch gapopen bitscore stitle"],stdout=subprocess.PIPE).wait()

解决方法

可能实际的问题是您设置了 stdout=subprocess.PIPE 但随后忽略了输出。如果要丢弃任何输出,请使用 stdout=subprocess.DEVNULL;如果你想让子进程正常写入标准输出,就不要设置stdout

是否使用 shell=True(以及由单个字符串组成的第一个参数供 shell 解析)与否(在这种情况下,第一个参数应该是正确标记化的字符串列表)与等待子进程。

您通常应该避免Popen,它默认不等待。 subprocess.run() 及其旧表亲 check_call() 等。等待外部子进程。

通常,如果可以,可能会避免使用 shell=True

def blast(file):
    subprocess.run(
        ['blastn','-query,' f'{output_path}fasta_files/{file}','-db',db_path,'-max_hsps','1','-max_target_seqs','40','-num_threads','4','-evalue','1e-5 ','-out',f'{output_path}blast/{file[:-2]}txt','-outfmt' "6 qseqid sseqid pident staxids sskingdoms qstart qend "
                    "qlen length sstart send slen evalue mismatch gapopen "
                    "bitscore stitle"],stdout=subprocess.DEVNULL,check=True)

你创建的子进程将被等待,但当然它仍然有可能创建了自己的分离子进程,如果子进程对调用者隐藏了这个,Python不能直接等待。

顺便说一句,您的 if __name__ == '__main__' 代码应该是微不足道的;如果你把所有有用的代码都放在这个块中,无论如何,这个文件对 import 到另一个脚本是没有用的,所以整个 __name__ 检查是没有意义的。这样做的目的是让你可以说

def useful_code():
    # lots of code here

if __name__ == '__main__':
    useful_code()

现在,如果您 python scriptname.py,那么 __name__ 将是 __main__,因此对 useful_code() 的调用将立即执行。但是如果你 import scriptname(假设你已经设置好你可以这样做,使用正确的 sys.path 等等)不会导致 useful_code 立即运行;相反,调用者决定他们是否以及何时真正想要运行这个函数(或模块中的其他一些函数,如果它包含多个)。

另外,f'{file}' 只是表示 file(或 str(file),如果变量还不是字符串)的一种非常笨拙的方式。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...