如何将字典作为命令行参数传递给Python脚本?

69
如何将字典作为命令行参数传递给Python脚本? 我需要获取一个字典,其中键是字符串,值是某些元素的列表 - 例如看起来像这样:
command_line_arguments = {"names" : ["J.J.", "April"], "years" : [25, 29]}

我尝试过像这样

if __name__ == '__main__':
    args = dict([arg.split('=') for arg in sys.argv[2:]]) # also tried with 1 but doesn't work
    main(args)

我正在调用脚本,如下所示:

$ python saver.py names=["J.J.", "April"] years=[25, 29]

但是它不起作用,字典长度为0,需要2。有人可以帮助我通过并在主函数中创建字典吗?


1
http://docs.python.org/dev/library/argparse.html - Joran Beasley
相关问题:将字典作为参数通过SSH传递给Python脚本 - Martin Prikryl
9个回答

101

需要注意的重点是,在命令行中你不能将Python对象作为参数传入。你当前使用的shell将解析这些参数并根据自己的参数解析规则进行传递。

也就是说,你不能传递一个Python字典。然而,诸如JSON之类的东西可以让你接近实现这一点。

JSON - 或JavaScript对象表示法 是一种将Python对象转换成类似于字符串的表示形式的方法,适合用于多种语言的传递。也就是说,你可以传递这样一个字符串:

python saver.py '{"names": ["J.J.", "April"], "years": [25, 29]}'

在你的 Python 脚本中,执行以下操作:

import json
data=json.loads(argv[1])

这将返回一个代表您想要传递的数据的字典。

同样,您可以取回一个 Python 字典并将其转换为字符串:

import json
data={'names': ["J.J.", "April"], 'years': [25,29]}
data_str=json.dumps(data)

还有其他方法可以完成这个任务,但JSON相对通用。需要注意的关键一点是,无论你使用什么方式,你都不会将字典传递到Python中,而是会传递一组参数(全都是字符串),然后你需要将它们转换为你需要的Python类型。

@EvanZamir - 请注意,在shell中,如果引号出现在引用的字符串中,通常需要对它们进行转义。在我的示例中,我使用单引号引用JSON数据,而json字符串本身使用双引号,因此无需使用引号。

如果您混合使用引号(使用双引号引用参数,并在其中使用双引号),那么shell将要求您对其进行转义,否则它遇到的第一个双引号将被视为该参数的“关闭引号”。请注意,在本示例中,我使用单引号来包含JSON字符串,而在字符串中使用双引号。如果我在字符串中使用单引号,则需要使用反斜杠进行转义,即:

python saver.py '{"names": ["J.J.", "April\'s"], "years": [25, 29]}'
或者
python saver.py "{\"names\": [\"J.J.\", \"April's\"], \"years\": [25, 29]}"

请注意引用的内容是您的Shell函数,因此可能会有所不同(例如,如果您使用某些执行方法调用脚本,则可能不需要转义,因为可能不会调用bash shell。)


我在CentOS 6.4,KDE Konsole和tcsh shell上尝试了这个,不知道为什么它不起作用。Python版本是2.6.6。sys.argv看起来像这样[filename,names',"J.J.", "April", 'years',25,29] - Shuman
3
这个方法很有效,但别忘了要转义引号,否则Python就不会识别它们。例如,我必须这样做:--names "{\"names\": [\"J.J.\", \"April\"], \"years\": [25, 29]}" - cjbarth
1
请注意,以下是关于编程的内容。将以下英文内容翻译成中文:注意单引号括起来的参数——这样可以避免在命令行中转义双引号。请返回已翻译的文本。 - chander
@chander,这似乎不起作用,例如在PyCharm中提交参数。我不得不使用转义。 - Evan Zamir
@EvanZamir - 请注意(通常情况下),在shell中,如果引号出现在引用的字符串中,则需要对其进行转义。在我的示例中,我使用单引号引用JSON数据,并且json字符串本身使用双引号,从而避免了引号的需要。如果您混合使用引号(使用双引号引用参数和内部的双引号),则必须对其进行转义,否则它遇到的第一个双引号将被视为参数的“结束引号”。由于您正在经历的行为是shell的函数,而不是Python的函数,因此可能会有所不同。 - chander
@cjbarth请查看关于引号在shell中如何工作的更新。 - chander

15

这里有另一种使用 stdin 的方法。这是你需要用于 json cgi 接口的方法(例如,让 Web 服务器将请求传递给你的脚本):

Python:

 import json, sys
 request = json.load( sys.stdin )
...

在Linux终端中测试您的脚本:

echo '{ "key1": "value 1", "key2": "value 2" }' | python myscript.py

为了从Windows终端测试您的脚本:

echo { "key1": "value 1", "key2": "value 2" } | python myscript.py

2

请按以下方式传递命令行参数(注意单引号和双引号):

"{'k1':'v1','k2':['v1','v2',1,2,3]}"

然后在您的 Python 代码中使用 eval() 或 ast.literal_eval()。

import ast
if __name__=="__main__":
     cmd_arg=sys.argv[1]
     print(ast.literal_eval(cmd_arg))
     print(type(ast.literal_eval(cmd_arg)))

 

这不是 @Bishamon 的回答 已经展示了吗? - Martin Prikryl
1
我专注于命令行参数语法,"{"k","v"}"会导致错误...并且还使用了ast.literal_eval()函数。 - Tomato Master

2

虽然我的回答有点晚了,但我发现这里的大多数答案都存在某种漏洞或不必要的繁琐。我也需要将字典字符串作为命令行参数传递。因此,以下是最简单和最可靠的方法。它适用于Linux和Windows。在名为somepyfile.py的Python文件中输入以下内容:

import sys
from ast import literal_eval

i = sys.argv[1]
a = literal_eval(i)
print(a)
print(type(a))

现在在终端中按照以下方式操作:

python somepyfile.py {'hello':4}

简单吧!

2
你不觉得 eval 有它自己的“漏洞”吗? - Martin Prikryl
可能存在危险,但使用literal_eval()可以更安全,我会添加的。 - Gringo Suave

2
我是一个有用的助手,可以将文本翻译成中文。
我最初使用了@chander的出色答案,但在特殊字符转义方面遇到了问题,无论是在shell/command层面还是在Python脚本内部。将JSON保存到文件中,然后将该文件名作为参数传递给脚本可能是一种解决方案,但在我的情况下,这将会相当复杂。
因此,我决定在参数级别对字符串进行URL编码,并在Python脚本内部对其进行解码。这意味着调用Python脚本的任何内容都需要对作为JSON字符串的命令行参数进行URL编码。有许多在线工具可让您沙盒式地使用URL编码字符串。在我的情况下,一个nodejs脚本调用Python脚本调用并且可以轻松地对JSON进行URL编码。
在Python脚本内部,它看起来像这样(您不必使用argparse,但我喜欢它):
import json
import argparse
from urllib.parse import unquote

# Set up CLI Arguments
parser = argparse.ArgumentParser()

# Required Arguments
parser.add_argument("-c", "--config", required=True,
                    help="JSON configuration string for this operation")

# Grab the Arguments
args = parser.parse_args()

jsonString = unquote(args.config)

print(jsonString)

config = json.loads(jsonString)

print(config)

对我来说有效,但需要记住这里的键和值应该用双引号 (") 而不是单引号 (')。 - ArieAI
@编辑:实际上,不带 'unquote' 也可以。 - ArieAI

0

这应该可以工作:

script = ["python2.7", os.path.join(os.path.dirname(__file__), "xs_helper.py"), '\'%s\'' % json.dumps(dicData)]

0
有时候你只需要一些简单的东西,不需要json甚至literal_eval:
import sys

dict_arg = sys.argv[1]
result = dict( pair.split('=') for pair in dict_arg.split(',') )

print(result)

在那里加入几个.strip()就可以处理额外的空格。

⏵ python3 parse.py 'foo=bar,number=6'
{'foo': 'bar', 'number': '6'}

0

按照以下步骤,无需为Python转义双引号或单引号即可将JSONDictionary作为命令行参数读取:

像这样导入 Python 的 Windows32 API 模块:
import win32.win32api

如果你没有安装该模块,可以输入 pip install pywin32 命令来在你的机器上安装它。

要读取命令行参数,请使用以下代码,命令行参数的值将作为字符串存储在变量 cmdArguments 中:

cmdArguments = win32.win32api.GetCommandLine()

始终将 JSON/字典 作为命令行参数的最后一个参数传递是一种好习惯。例如,如果你已经将 JSON/字典 作为命令行中的最后一个参数传递,则下面的行可以将 JSON/字典 作为单独的参数提取出来,并将其存储在名为 jsonstr 的变量中:

jsonstr = ' '.join(cmdArguments.split(' ')[4:])

技术上讲,由于有空格,所以该对象被拆分成单独的参数,我们需要将它们合并为一个参数。

现在,如果你打印 jsonstr 的值,你将得到与命令行参数中传递的相同的 JSON/字典

这是一个完整的示例代码:

import json
import win32.win32api
cmdArguments = win32.win32api.GetCommandLine()
jsonstr = ' '.join(cmdArguments.split(' ')[4:])
print(json.loads(jsonstr)) #为确保打印相同的JSON/字典对象,使用json.loads()将JSON转换为DICT,如果需要JSON对象,则可以忽略json.loads()。

示例命令行参数如下,其中 NameOfProgram 是 Python 脚本的名称:

py <NameOfProgram.py> {"Name":"Sample Name","Salary":"20 k","Class":"First-Class"}

现在的输出结果将会是:

{'Name':'Sample Name','Salary':'20 k','Class':'First-Class'}

-1

我遇到了同样的问题,适用于我的方法是使用反斜杠例如:

"{\"key\": \"value\", \"key2\": [{\"key3\":\"value\"}, ... ]}"

附注:在Windows终端(CMD)和Bash(Git Bash)中进行了测试


1
最受欢迎的答案之一包含这些说明,如果您希望表明这种方法对您也起作用,请使用评论功能。 - Mixone
最受欢迎的答案之一包含这些说明,如果您希望表明这种方法对您也起作用,请使用评论功能。 - Mixone
这并没有真正回答问题。如果您有不同的问题,可以通过点击提问来提出。如果您想在此问题获得新的答案时得到通知,您可以关注此问题。一旦您拥有足够的声望,您还可以添加悬赏以吸引更多关注。- 来自审核 - Sunderam Dubey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接