我建议不要将复杂数据作为 CL 参数传递,而是通过 STDIN/STDOUT 管道传输您的数据 - 这样您就不必担心转义特殊的、shell 有效的字符和超过最大命令行长度。
通常,作为基于 CL 参数的脚本,您可能会有类似 app.py:
import sys
if __name__ == "__main__": # ensure the script is run directly
if len(sys.argv) > 1: # if at least one CL argument was provided
print("ARG_DATA: {}".format(sys.argv[1])) # print it out...
else:
print("usage: python {} ARG_DATA".format(__file__))
它显然希望传递一个参数,如果从另一个脚本传递,它会打印出来,比如caller.py:
import subprocess
out = subprocess.check_output(["python", "app.py", "foo bar"]) # pass foo bar to the app
print(out.rstrip()) # print out the response
# ARG_DATA: foo bar
但是如果你想传递更复杂的东西,比如dict,该怎么办?由于dict 是一个层次结构,我们需要一种方法将其呈现在一行中。有很多格式可以满足要求,但让我们坚持使用基本 JSON,因此您可能会将您的 caller.py 设置为这样的:
import json
import subprocess
data = { # our complex data
"user": {
"first_name": "foo",
"last_name": "bar",
}
}
serialized = json.dumps(data) # serialize it to JSON
out = subprocess.check_output(["python", "app.py", serialized]) # pass the serialized data
print(out.rstrip()) # print out the response
# ARG_DATA: {"user": {"first_name": "foo", "last_name": "bar"}}
现在,如果您修改 app.py 以识别它接收 JSON 作为参数的事实,您可以将其反序列化回 Python dict 以访问其结构:
import json
import sys
if __name__ == "__main__": # ensure the script is run directly
if len(sys.argv) > 1:
data = json.loads(sys.argv[1]) # parse the JSON from the first argument
print("First name: {}".format(data["user"]["first_name"]))
print("Last name: {}".format(data["user"]["last_name"]))
else:
print("usage: python {} JSON".format(__file__))
如果你再次运行caller.py,你会得到:
名字:foo
姓氏:酒吧
但这非常乏味,而且 JSON 对 CL 不是很友好(在幕后 Python 进行了大量的转义以使其工作)更不用说 JSON 的大小有限制(取决于操作系统和 shell)可以通过这种方式。使用 STDIN/STDOUT 缓冲区在进程之间传递复杂数据要好得多。为此,您必须修改 app.py 以等待其 STDIN 上的输入,并让 caller.py 向其发送序列化数据。所以,app.py 可以这么简单:
import json
if __name__ == "__main__": # ensure the script is run directly
try:
arg = raw_input() # get input from STDIN (Python 2.x)
except NameError:
arg = input() # get input from STDIN (Python 3.x)
data = json.loads(arg) # parse the JSON from the first argument
print("First name: {}".format(data["user"]["first_name"])) # print to STDOUT
print("Last name: {}".format(data["user"]["last_name"])) # print to STDOUT
和caller.py:
import json
import subprocess
data = { # our complex data
"user": {
"first_name": "foo",
"last_name": "bar",
}
}
# start the process and pipe its STDIN and STDOUT to this process handle:
proc = subprocess.Popen(["python", "app.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
serialized = json.dumps(data) # serialize data to JSON
out, err = proc.communicate(serialized) # send the serialized data to proc's STDIN
print(out.rstrip()) # print what was returned on STDOUT
如果你调用caller.py,你会再次得到:
名字:foo
姓氏:酒吧
但是这次你传递给app.py的数据大小没有限制,你不必担心在shell转义等过程中某种格式会被搞砸。你也可以保留“通道”打开并让两个进程以双向方式相互通信 - 以 this answer 为例。