argparse.add_argument() 中的 type=dict
我想使用标准库 argparse 模块来解析我的程序的命令行参数,并让程序接受可选参数 -i
(或 --image
)这是一本字典。
我尝试像这样配置解析器:
parser.add_argument('-i','--image', type=dict, help='Generate an image map from the input file (syntax: {\'name\': <name>, \'voids\': \'#08080808\', \'0\': \'#00ff00ff\', \'100%%\': \'#ff00ff00\'}).')
但是当我尝试运行脚本时,出现错误:
$ ./script.py -i {'name': 'img.png','voids': '#00ff00ff','0': '#ff00ff00','100%': '#f80654ff'}
script.py: error: argument -i/--image: invalid dict value: '{name:'
即使类似的语法在解释器中也可以正常工作:
>>> a={'name': 'img.png','voids': '#00ff00ff','0': '#ff00ff00','100%': '#f80654ff'}
我应该如何a)编写命令行和b)设置 argparse
逻辑?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
破坏这个:
json.loads
在这里也可以工作。看起来也不是太脏。返回:
{u'0': u'#ff00ff00', u'100%': u'#f80654ff', u'voids': u'#00ff00ff', u'name': u'img.png '}
Necroing this:
json.loads
works here, too. It doesn't seem too dirty.Returns:
{u'0': u'#ff00ff00', u'100%': u'#f80654ff', u'voids': u'#00ff00ff', u'name': u'img.png'}
为了完整起见,与 json.loads 类似,您可以使用 yaml.load (可从 PyPI 中的 PyYAML 获取)。这比 json 具有优势,因为不需要在命令行上引用各个键和值,除非您试图将整数强制转换为字符串或以其他方式克服 yaml 转换语义。但显然整个字符串需要引用,因为它包含空格!
尽管不可否认,在给出的问题中,许多键和值都必须被引用或重新措辞,以防止 yaml 崩溃。如果您需要数字而不是字符串值,那么使用以下数据似乎效果很好:
For completeness, and similarly to json.loads, you could use yaml.load (available from PyYAML in PyPI). This has the advantage over json in that there is no need to quote individual keys and values on the command line unless you are trying to, say, force integers into strings or otherwise overcome yaml conversion semantics. But obviously the whole string will need quoting as it contains spaces!
Although admittedly in the question given, many of the keys and values would have to be quoted or rephrased to prevent yaml from barfing. Using the following data seems to work quite nicely, if you need numeric rather than string values:
使用简单的 lambda 解析非常灵活:
Using simple lambda parsing is quite flexible:
我敢打赌你的 shell 弄乱了大括号,因为大括号是许多 shell 中用于大括号扩展功能的语法(请参阅 此处)。
在命令行界面中,传递诸如字典之类的复杂容器,要求用户了解 Python 语法,这似乎是一个糟糕的设计选择。相反,我建议在 CLI 中的 参数组,然后从解析的组中以编程方式构建字典。
I’ll bet your shell is messing with the braces, since curly braces are the syntax used for brace expansion features in many shells (see here).
Passing in a complex container such as a dictionary, requiring the user to know Python syntax, seems a bad design choice in a command line interface. Instead, I’d recommend just passing options in one-by-one in the CLI within an argument group, and then build the dict programmatically from the parsed group.
结合 @Edd 的 type= 片段和 @Bradley 的 ast.literal_eval 片段产生最直接的解决方案,IMO。它允许直接检索 argval,甚至采用 dict 的(带引号的)默认值:
代码片段
运行代码,
请注意 dict 值上的引号。此引用适用于 Windows 和 Linux(使用 [t]csh 测试)。
找回阿格瓦尔
Combining the
type=
piece from @Edd and theast.literal_eval
piece from @Bradley yields the most direct solution, IMO. It allows direct retrieval of the argval and even takes a (quoted) default value for the dict:Code snippet
Running the Code
note the quotes on the dict value. This quoting works on Windows and Linux (tested with [t]csh).
Retrieving the Argval
你绝对可以将看起来像字典文字的东西输入到参数解析器中,但是你必须引用它,这样当 shell 解析你的命令行时,它就会作为
所以像这样的东西可以将您想要的文本放入您的程序中:
但是,这个字符串不是 dict 构造函数的有效参数;相反,它是一个有效的 python 代码片段。你可以告诉你的参数解析器这个参数的“类型”是
eval
,这将起作用:并调用它:
但这并不安全;输入可以是任何东西,并且您正在评估任意代码。它同样笨重,但下面的方法会更安全:
这也有效,但对允许进行
eval
'的限制要严格得多。尽管如此,让用户在命令行上输入一些看起来像 Python 字典的内容并正确引用是非常不方便的。而且,您必须在事后进行一些检查,以确保它们传递的是字典而不是其他可评估的内容,并且其中包含正确的键。如果满足以下条件,则使用起来会更容易:
对于:
You can definitely get in something that looks like a dictionary literal into the argument parser, but you've got to quote it so when the shell parses your command line, it comes in as
So something like this can get the text you wanted into your program:
However, this string is not a valid argument to the dict constructor; instead, it's a valid python code snippet. You could tell your argument parser that the "type" of this argument is
eval
, and that will work:and calling it:
But this is not safe; the input could be anything, and you're evaluating arbitrary code. It would be equally unwieldy, but the following would be much safer:
This also works, but is MUCH more restrictive on what it will allow to be
eval
'd.Still, it's very unwieldy to have the user type out something, properly quoted, that looks like a python dictionary on the command line. And, you'd have to do some checking after the fact to make sure they passed in a dictionary instead of something else eval-able, and had the right keys in it. Much easier to use if:
For:
我发现的最简单的方法之一是将字典解析为列表,然后将其转换为字典。例如使用Python3:
那么你可以在命令行上输入类似:
以获得所需的结果:
One of the simplest ways I've found is to parse the dictionary as a list, and then convert that to a dictionary. For example using Python3:
then you can type on the command line something like:
to get the desired result:
从命令行将参数作为字典传递的最小示例:
在终端中,您可以使用字符串格式将参数作为字典传递:
A minimal example to pass arguments as a dictionary from the command line:
and in the terminal you can pass your arguments as a dictionary using a string format:
一般建议:不要使用 eval。
如果你真的必须......
“评估”是危险的。如果您确定没有人会故意输入恶意输入,请使用它。即便如此,也可能存在缺点。我举了一个不好的例子。
使用 eval 代替 json.loads 也有一些优点。字典实际上不需要是有效的 json。因此,eval 在接受“字典”方面可以相当宽松。我们可以通过确保最终结果确实是一个 python 字典来处理“危险”部分。
输出:
General Advice: DO NOT USE eval.
If you really have to ...
"eval" is dangerous. Use it if you are sure no one will knowingly input malicious input. Even then there can be disadvantages. I have covered one bad example.
Using eval instead of json.loads has some advantages as well though. A dict doesn't really need to be a valid json. Hence, eval can be pretty lenient in accepting "dictionaries". We can take care of the "danger" part by making sure that final result is indeed a python dictionary.
Output:
您可以尝试:
我还没有在我的手机上测试过这个。
编辑:顺便说一句,我同意@wim,我认为将字典的每个 kv 作为参数对用户来说会更好。
You could try:
I haven't tested this, on my phone right now.
Edit: BTW I agree with @wim, I think having each kv of the dict as an argument would be nicer for the user.
这是另一个解决方案,因为我自己也必须做类似的事情。我使用
ast
模块将字典(作为字符串输入到终端)转换为字典。这很简单。代码片段
假设以下内容被称为
test.py
:然后在终端/cmd 行中,您将编写:
运行代码
输出
Here is a another solution since I had to do something similar myself. I use the
ast
module to convert the dictionary, which is input to the terminal as a string, to a dict. It is very simple.Code snippet
Say the following is called
test.py
:Then in the terminal/cmd line, you would write:
Running the code
Output
TLDR 解决方案:
最简单、最快的解决方案如下:
在
parser.add_argument
函数中:str
作为类型然后
args.parameters 将自动转换为字典,无需使用
ast.literal.eval
或json.loads
。动机:
当
default
设置为 json 编码字典(如下所示)时,@Galuoises 和 @frankeye 发布的方法似乎不起作用。这是因为
TLDR Solution:
The simplest and quickest solution is as below:
In the
parser.add_argument
function:str
as the typeThen
args.parameters
will automatically be converted to a dictionary without any need forast.literal.eval
orjson.loads
.Motivation:
The methods posted by @Galuoises and @frankeye, appear to not work when the
default
is set as a json encoded dictionary such as below.This is because
以下工作正常:
对于默认值,类型应该是 dict 因为 json.loads 返回字典,而不是字符串,默认对象应该作为字典给出。
The following works just fine:
For default value, the type should be dict since json.loads returns a dictionary, not a string, the default object should be given as a dictionary.
就我而言,我需要传递具有多个值的标签列表,并且我想将它们作为字典获取。所以我结合了 nargs 和 Action 来做到这一点:
参数行:
带来了字典:
In my case I need to pass list of labels with multiple values and I wanted to get them as dictionary. So I did it with combination of
nargs
andAction
:And the line of arguments:
brings the dictionary:
我意识到这是一个古老的问题,但没有一个答案能解决我的具体情况。如果我错过了一些明显的事情,请提前道歉,但我的 Python 编码经验不到 7 天。
我的例子是一本字典,其中的值本身可以是字典。例如下面的简单示例:
由于字典的字典似乎是一个合法的构造,因此我认为将我可能的解决方案添加到已经很长的解决方案列表中是有意义的。
这种情况没有由 json 解决方案处理,如下所示:
返回:
这种情况没有由 yaml 解决方案处理,如下所示:
返回:
我发现 ast.literal_eval 解决方案确实有效,但未能实际检查它传递了一个字典,如下所示:
返回:
据我了解,add_argument() 的“type”参数的要点是对该参数进行类型检查。我不会声称以下解决方案是防弹的,但我确实相信它可以正确处理字典的字典情况,并且如果将字典以外的内容传递给它,则应该返回用法。对之前的答案的所有应有的尊重,因为我只能根据我对与使用 lambda 和 ast.literal_eval() 相关的两个先前答案的理解和组合来将其拼凑在一起。我希望它对我以外的人有用。
返回:
I realize this is an ancient question, but none of the answers handled my specific case. Apologies in advance if I missed something obvious, but my python coding experience consists of less than 7 days.
My case was a dictionary where the values could themselves be dictionaries. Such as the following simple example:
Since a dictionary of dictionaries seems to be a legal construct, I thought it made sense to add my possible solution to the already long list of solutions.
This case wasn't handled by the json solution as shown below:
Returned:
This case wasn't handled by the yaml solution as shown below:
Returned:
I found that the ast.literal_eval solution did work, but failed to actually check that it was passed a dictionary as shown below:
Returns:
As I understood it, the point of "type" argument to add_argument() was to do type checking for that argument. I will not claim that the following solution is bullet proof, but I do believe that it correctly handles the dictionary of dictionaries case and should return usage if something other than a dictionary is passed to it. All due respect to previous answers because I was only able to piece this together from my understand of, and the combining of, two previous answers related to using lambda and ast.literal_eval(). I hope it is useful to someone other than me.
Returns: