【问题标题】:return a variable value from a subprocess in python从python中的子进程返回一个变量值
【发布时间】:2015-06-22 14:39:57
【问题描述】:

我有一个代码工作流程,其中我从一个主脚本(级别 0)通过subprocess 调用另一个脚本。这个subprocess script(级别1)又调用另一个脚本作为subprocess。现在,从这个 2 级子进程脚本中,我想将一个变量的值返回到主脚本(0 级)。我已经尝试过Popen.communicate(),但我无法返回该值。我目前的代码是:

ma​​in_script.py

def func():

    para = ['a','b']
    result = subprocess.Popen([sys.executable,"first_subprocess.py"]+para,stdout=subprocess.PIPE)
    result.wait()

    return_code = result.returncode
    out, err = sub_result.communicate()


    if return_code == 1:
        return return_code

    else:
        if out is not None:
            print 'return value: ', out


if __name__ == '__main__':

    func()

上面的脚本叫做first_subprocess.py,它有:

def some_func():

    # some other code and multiple print statements

    para = ['a','b']
    result = subprocess.Popen([sys.executable,"second_subprocess.py"]+para,stdout=subprocess.PIPE)

    result.wait()
    out, err = result.communicate()
    return_code = sub_result.returncode
    if return_code == 0:
        return out


if __name__ == '__main__':

    some_func()

second_subprocess.py 返回如下值:

def test():
    # some other code and multiple print statements
    val = 'time'
    print 'returning value'
    return val   

if __name__ == '__main__':    

    test()

当我尝试上面的代码时,我将代码中的所有 print 语句作为输出而不是返回值。即使尝试print subprocess 中的变量值而不是返回它也不会达到目的,因为有多个打印语句。

在这种情况下如何返回变量值?

更新版本:

根据@Anthons 的建议,我修改了我的first_subprocess.py 脚本和main_script.py,如下所示:

first_subprocess.py:

def some_func():

   try:
    key = None
    if not (key is None):

       para = ['a','b']
       result = subprocess.Popen([sys.executable,"second_subprocess.py"]+para,stdout=subprocess.PIPE)

       sub_result.wait()
       out, err = sub_result.communicate()
       return_code = sub_result.returncode
       if return_code == 0:
       for line in out.splitlines():
           if not line.startswith('>>>'):
              continue
           print line
   else:
     sys.exit(0)
 except:
   return 1

Main_script.py:

if out is not None:
   for line in out.splitlines():
       if not line.startswith('>>>'):
          continue
      value = line.split(':',1)[1].lstrip()

print 'return value:',value`

当我在上面执行时,我在print value 命令中得到UnboundLocalError: local variable 'value' referenced before assignment。似乎如果我不执行 1 级脚本中的代码并执行 sys.exit() 那么主脚本中的 out 既不是空的也不是空的,但它有一些未定义的值,因此 value 变量没有得到初始化并抛出错误

【问题讨论】:

  • 更新后的 first_subprocess.py 无法运行。也许您的缩进没有正确转移。像这样的一般try:except 隐藏了正在发生的所有错误,这是非常糟糕的风格。 key = None 在那里做什么?
  • @Anthon 那是错误的。我已经更正了缩进。 key = None 只是一个演示,显示代码将在不执行底层代码的情况下退出。我保留了try: except 以捕捉可能出现的任何错误。上面的代码只是实际代码的一部分。我一直在尝试捕获我上面没有发布的其余代码

标签: python python-2.7 subprocess


【解决方案1】:

如果您只想返回一个整数值,您可以使用退出值。这与从some_func() 返回的情况不同,您必须执行sys.exit(integer_val)

如果你想返回一个像time 这样的字符串,你应该打印它(或写到sys.stdout),然后在调用进程(级别1)中解析子进程的输出并将其打印到它自己的标准输出中0级才能看到。

在您的情况下,第二级应该执行以下操作:

def test():
    # some other code and multiple print statements
    val = 'time'
    print 'returning value:', val

if __name__ == '__main__':    
    test()

在第 1 级你会做:

def some_func():

    # some other code and multiple print statements

    para = ['a','b']
    result = subprocess.Popen([sys.executable,"second_subprocess.py"]+para,stdout=subprocess.PIPE)

    result.wait()
    out, err = result.communicate()
    return_code = sub_result.returncode
    if return_code == 0:
        print out

if __name__ == '__main__':
    some_func()

有了这个 main_script.py 可以从你的 1 级脚本的调用中读取一些内容。

我通常使用subprocess.check_output() 来传递这些信息。如果被调用进程具有非零退出状态(即出错),则会引发异常。我还可以建议,如果子进程写入的信息不仅仅是变量,您可以通过在行首返回一些独特的内容来轻松解析输出行(因此您仍然可以使用打印语句来调试各个脚本 从输出中获取正确的值):

2 级:

def test():
    # some other code and multiple print statements
    print 'debug: Still going strong'
    val = 'time'
    print '>>>> returning value:', val

if __name__ == '__main__':    
    test()

1 级:

...
out, err = result.communicate()
for line in out.splitlines():
    if not line.startswith('>>>>'):
        continue
    print line
...

0级:

...
out, err = result.communicate()
for line in out.splitlines():
    if not line.startswith('>>>>'):
        continue
    try:
        value = line.split(':', 1)[1]
    except IndexError:
        print 'wrong input line', repr(line)
    print 'return value: ', value
...

以下文件一起使用。以指定的名称保存它们

lvl2.py

# lvl2
import sys

def test():
    # some other code and multiple print statements
    print >> sys.stderr, 'argv', sys.argv[1:]
    print 'debug: Still going strong'
    val = 'time'
    print '>>>> returning value:', val
    return 0

if __name__ == '__main__':
    sys.exit(test())

lvl1.py

# lvl1.py
import sys
import subprocess

def some_func():
    para = ['a','b']
    sub_result = subprocess.Popen(
        [sys.executable, "lvl2.py" ] + para,
        stdout=subprocess.PIPE)
    sub_result.wait()
    out, err = sub_result.communicate()
    return_code = sub_result.returncode
    if return_code == 0:
        for line in out.splitlines():
            if not line.startswith('>>>'):
                continue
            print line
    else:
        print >> sys.stderr, 'level 2 exited with' + return_code
    sys.exit(0)

if __name__ == '__main__':
    sys.exit(some_func())

lvl0.py

# lvl0
import subprocess
import sys

def func():
    para = ['a','b']
    result = subprocess.Popen(
        [sys.executable, "lvl1.py"] + para,
        stdout=subprocess.PIPE)
    result.wait()
    return_code = result.returncode
    out, err = result.communicate()

    value = None
    if return_code == 0:
        for line in out.splitlines():
            if not line.startswith('>>>'):
                continue
            value = line.split(':',1)[1].lstrip()
            print
    else:
        print 'non-zero exit', return_code
    print 'return value:', value

if __name__ == '__main__':
    func()

然后运行python lvl0.py检查输出是否为

argv ['a', 'b']

return value: time

现在将这些置于您的版本控制系统之下,并开始一次更改几行,每次运行 python lvl0.py 以检查您可能破坏了什么。提交每个修订版,以便您可以回滚到上一个“已知良好”状态并慢慢引入其余代码。

【讨论】:

  • 我尝试使用 print 而不是 return 就像你展示的那样,但问题是我在两个脚本的其余代码中已经有多个打印语句。因此,所有这些打印语句也都通过了。
  • @JasonDonnald 确保你的变量行有一些独特的东西。然后在调用程序中执行for line in out.splitlines() 并跳过不以唯一字符串开头的行。
  • 所以如果像上面这样说我有 print 'returning value', val 作为 2 级脚本中的唯一行,那么我如何在 main_script 代码中提取它?如果您可以修改您的答案,那将会很有帮助
  • @JasonDonnald 我扩展了我的答案,但我没有运行确切的脚本(片段)。我希望这些片段以及将它们放在哪里是有意义的。您应该能够运行各个脚本并获得完整的输出,并且只有以“>>>>”开头的行在“通过”级别 1 上传递
  • 当我尝试您的上述修改时,我在_, value = line.split(':', 1)[1] 得到IndexError: list index out of range
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多