【问题标题】:how to add a list, passed from a subprocess to parent process, to an already existing list in python如何将从子进程传递到父进程的列表添加到python中已经存在的列表
【发布时间】:2015-09-23 21:21:49
【问题描述】:

我正在将一个列表从subprocess 传递给父进程,并且在父进程中我想将它添加到一个已经存在的列表中。我这样做了:

subprocess_script.py:

def func():

    list = []
    list.append('1')
    list.append('2')

    print'Testing the list passing'
    print '>>> list:',list

if __name__ == '__main__':
     func()

parent_script.py:

list1 = []
list1.append('a')
list1.append('b')
ret = subprocess.Popen([sys.executable,"/Users/user1/home/subprocess_script.py"],stdout=subprocess.PIPE)
ret.wait()

return_code = ret.returncode
out, err = ret.communicate()
if out is not None:
        for line in out.splitlines():

            if not line.startswith('>>>'):
                continue
            value = line.split(':',1)[1].lstrip()
            list1.extend(value)
print 'Final List: ',list1

但是当我执行这个时,我没有得到想要的输出。我想要的最终列表应该是:['a','b','1','2']。但我得到['a', 'b', '[', "'", '1', "'", ',', ' ', "'", '2', "'", ']'] 这是错误的。我在这里做错了什么?

【问题讨论】:

  • 仅供参考,使用隐藏 Python 内置函数的变量名(此处为 list)并不是一个好习惯。

标签: python list subprocess output


【解决方案1】:

问题在于,在您的splitlstrip 调用之后,value 仍然是一个字符串,而不是一个列表。您可以停止包含 pdb.set_trace 行的脚本并像这样检查它:

if not line.startswith('>>>'):
    continue
import pdb; pdb.set_trace()
value = line.split(':', 1)[1].lstrip()
list1.extend(value)

然后运行代码:

❯ python main.py
> /private/tmp/example/main.py(19)<module>()
-> value = line.split(':', 1)[1].lstrip()
(Pdb) line
">>> list: ['1', '2']"
(Pdb) line.split(':', 1)[1].lstrip()
"['1', '2']"

您可以使用 ast.literal_eval 函数将该字符串计算为 Python 列表,如下所示:

(Pdb) import ast
(Pdb) ast.literal_eval(line.split(':', 1)[1].lstrip())
['1', '2']

现在list1 可以用这个值扩展。

来自the Python 2.7 documentation

ast.literal_eval(node_or_string)

安全地评估包含 Python 文字或容器显示的表达式节点或 Unicode 或 Latin-1 编码字符串。提供的字符串或节点只能由以下 Python 文字结构组成:字符串、数字、元组、列表、字典、布尔值和无。

这可用于安全地评估包含来自不受信任来源的 Python 值的字符串,而无需自己解析这些值。它无法评估任意复杂的表达式,例如涉及运算符或索引。

【讨论】:

  • 必须使用ipdb吗?没有这个就没有别的办法了吗?
  • @JasonDonnald :不,ipdb 根本不需要;我只是想准确地说明我做了什么。但是由于这可能会让您感到困惑,而且pdb 是 Python 附带的标准工具,所以我只是在pdb 中重新进行了调试。都是一样的。
  • 谢谢我知道了!您能否简要解释一下 ast.literal_eval() 是如何解决这个问题的?
【解决方案2】:

你做错了。

当你这样做时 - print '&gt;&gt;&gt; list:',list 。它会打印 -

>>> list: [1, 2]

当你这样做时 - value = line.split(':',1)[1].lstrip() ,值将成为字符串 -

'[1, 2]'

当使用 value 扩展 list1 时, value 中的每个字符都将作为一个新元素添加到 list1 中(因为它会遍历字符串的每个元素,即每个字符并将它们添加到list1)。

在创建值时,您希望删除第一个 [ 以及尾随的 ],然后根据 , 拆分它们。

示例代码-

value = line.split(':',1)[1].lstrip().lstrip('[').rstrip(']').replace("'",'').replace(" ",'').split(',')

上面的代码是一个非常大的黑客,最好使用ast.literal_eval作为@logc在他的回答中提到-

import ast
value = ast.literal_eval(line.split(":",1)[1].lstrip())

但请注意,ast.literal_eval 会评估表达式并返回结果,请谨慎使用。

【讨论】:

  • 将列表从子进程传递到父进程作为列表本身然后将​​其添加到父进程中的另一个列表的更好方法是什么?
  • 我只知道这种方式,试试我给的值线。
  • 当我使用你提到的更新时,我得到的最终列表为 - ['a', 'b', "'1'", " '2'"]。最后两个元素周围有一个额外的"
  • @JasonDonnald :正如@AnandSKumar 告诉你的那样,使用eval 函数总是有点安全问题。 ast.literal_eval 承诺是安全的,但您最好使用标准数据表示,例如 JSON。
【解决方案3】:

使用标准的序列化数据格式,如 JSON:

script.py

import json


def func():

    lst = []
    lst.append('1')
    lst.append('2')

    print json.dumps(lst)  ## <-- `dumps` dumps to a string

if __name__ == '__main__':
    func()

ma​​in.py

import sys
import os
import subprocess
import json

list1 = []
list1.append('a')
list1.append('b')
ret = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "script.py")], stdout=subprocess.PIPE)
ret.wait()

return_code = ret.returncode
out, err = ret.communicate()
line = next(line for line in out.splitlines())
value = json.loads(line)  ## <-- `loads` loads from a string
list1.extend(map(str, value))
print 'Final List: ', list1

map(str, value) 只是美观:它有一个统一的列表,因为默认情况下json.dumps 将生成 Unicode 字符串,而您之前的 list1 元素不是 Unicode 字符串。

另外,我删除了代码的整个页眉打印和跳行部分。和他们在一起你只会让你的生活变得更加艰难:)

【讨论】:

  • 如果假设第一个脚本中有多个打印语句(转储列表)并且其中只有一个带有转储,那么我如何将主脚本中的它与其他打印语句分开?在我的帖子中,如果您注意到我在 subprocess_script.py 中有两个打印语句。为了将它们分开,我在我想要的打印语句的开头添加了一个唯一标识符 &gt;&gt;&gt;,然后在父脚本中我正在检查以跳过其他打印语句
猜你喜欢
  • 2015-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
相关资源
最近更新 更多