函数中的 Subprocess.call() 不会暂停调用该函数的脚本
Subprocess.call() in a function doesn't pause the script that calls the function
我查看并找到了解决方案,尝试了它们并得到了相同的结果。我尝试使用 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)
如果变量不是字符串)。
我查看并找到了解决方案,尝试了它们并得到了相同的结果。我尝试使用 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)
如果变量不是字符串)。