函数中的 Subprocess.call() 不会暂停调用该函数的脚本 [英] Subprocess.call() in a function doesn't pause the script that calls the function

查看:68
本文介绍了函数中的 Subprocess.call() 不会暂停调用该函数的脚本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I looked and found solutions, tried them and got the same result. I tried using Popen.wait(), run() and call(). As suggested by other users, I also tried passing the command as a list of strings. Didn't work. The subprocess call doesn't give an error, so that's not the issue.

功能如下:

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')

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

Instead of passing a string I also tried passing a list:

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.

Probably the actual problem is that you were setting stdout=subprocess.PIPE but then ignoring the output. If you want to discard any output, use stdout=subprocess.DEVNULL; if you want to allow the subprocess to write to standard output normally, just don't set stdout at all.

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

Whether you use shell=True (and a first argument consisting of a single string for the shell to parse) or not (in which case the first argument should be a list of properly tokenized strings) has no bearing on whether the subprocess is waited for.

你通常应该避免 Popen,它默认不等待.subprocess.run() 和它的旧表兄弟 check_call() 等.等待外部子进程.

You should generally avoid Popen, which does not wait by default. subprocess.run() and its legacy cousins check_call() et al. do wait for the external subprocess.

通常,如果可以的话,可能会避免 shell=True.

Generally, probably avoid shell=True if you can.

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不能直接等待.

The subprocess you created will be waited for, but it is of course still possible that it created detached subprocesses of its own, which Python cannot directly wait for if the subprocess hides this from the caller.

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

As an aside, your if __name__ == '__main__' code should be trivial; if you put all the useful code in this block, there is no way the file can be useful to import into another script anyway, and so the whole __name__ check is pointless. The purpose of this is so you can say

def useful_code():
    # lots of code here

if __name__ == '__main__':
    useful_code()

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

Now, if you python scriptname.py, then __name__ will be __main__ and so the call to useful_code() will be executed immediately. But if you import scriptname (assuming you have set things up so that you can do this, with a correct sys.path and so forth) that will not cause useful_code to be run immediately; instead, the caller decides if and when they actually want to run this function (or some other function from the module, if it contains several).

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

As a further aside, f'{file}' is just a really clumsy way to say file (or str(file) if the variable wasn't already a string).

这篇关于函数中的 Subprocess.call() 不会暂停调用该函数的脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆