- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的用例是多个可选的位置参数,取自一组受限的 choices
,default
值是包含其中两个选项的列表。由于向后兼容问题,我无法更改界面。我还必须保持与 Python 3.4 的兼容性。
这是我的代码。您可以看到,我希望我的默认值是 choices
集合中的两个值的列表。
parser = argparse.ArgumentParser()
parser.add_argument('tests', nargs='*', choices=['a', 'b', 'c', 'd'],
default=['a', 'd'])
args = parser.parse_args()
print(args.tests)
所有这些都是正确的:
$ ./test.py a
['a']
$ ./test.py a d
['a', 'd']
$ ./test.py a e
usage: test.py [-h] [{a,b,c,d} ...]
test.py: error: argument tests: invalid choice: 'e' (choose from 'a', 'b', 'c', 'd')
这是不正确的:
$ ./test.py
usage: test.py [-h] [{a,b,c,d} ...]
test.py: error: argument tests: invalid choice: ['a', 'd'] (choose from 'a', 'b', 'c', 'd')
我发现了很多类似的问题,但没有一个是针对这个特定用例的。我发现(在不同的上下文中)最有希望的建议是编写自定义操作并使用它代替 choices
:
这并不理想。我希望有人能指出我错过的选项。
如果没有,我打算使用以下解决方法:
parser.add_argument('tests', nargs='*',
choices=['a', 'b', 'c', 'd', 'default'],
default='default')
只要我保持向后兼容性,我就可以添加参数。
谢谢!
更新:我最终采用了自定义操作。我很抗拒,因为这不像是一个需要自定义任何东西的用例。然而,这似乎或多或少是子类化 argparse.Action
的预期用例,它使意图非常明确,并提供了我发现的最干净的面向用户的结果。
class TestsArgAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
all_tests = ['a', 'b', 'c', 'd']
default_tests = ['a', 'd']
if not values:
setattr(namespace, self.dest, default_tests)
return
# If no argument is specified, the default gets passed as a
# string 'default' instead of as a list ['default']. Probably
# a bug in argparse. The below gives us a list.
if not isinstance(values, list):
values = [values]
tests = set(values)
# If 'all', is found, replace it with the tests it represents.
# For reasons of compatibility, 'all' does not actually include
# one of the tests (let's call it 'e'). So we can't just do
# tests = all_tests.
try:
tests.remove('all')
tests.update(set(all_tests))
except KeyError:
pass
# Same for 'default'
try:
tests.remove('default')
tests.update(set(default_tests))
except KeyError:
pass
setattr(namespace, self.dest, sorted(list(tests)))
最佳答案
标记为不正确的行为是由于原始默认值 ['a', 'd']
不在指定的 choices
内(参见: relevant code as found in Python 3.4.10 ;自 Python 3.10.3 起,此检查方法实际上没有变化)。我将从 Python argparse.py
源代码中复制代码:
def _check_value(self, action, value):
# converted value must be one of the choices (if specified)
if action.choices is not None and value not in action.choices:
args = {'value': value,
'choices': ', '.join(map(repr, action.choices))}
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
raise ArgumentError(action, msg % args)
当将默认值指定为列表时,整个值将传递给 _check_value
方法,因此它将失败(因为任何给定列表都不会匹配另一个列表中的任何字符串)。您实际上可以通过在该方法中使用 pdb
设置断点来验证这一点,并通过单步执行每一行来跟踪值,或者使用以下代码测试和验证规定的限制:
import argparse
DEFAULT = ['a', 'd']
parser = argparse.ArgumentParser()
parser.add_argument('tests', nargs='*', choices=['a', 'b', 'c', 'd', DEFAULT],
default=DEFAULT)
args = parser.parse_args()
print(args.tests)
然后运行python test.py
$ python test.py
['a', 'd']
这显然通过了,因为完全相同的 DEFAULT
值出现在 choices
列表中。
但是,调用 -h
或传递任何不受支持的值将导致:
$ python test.py z
usage: test.py [-h] [{a,b,c,d,['a', 'd']} ...]
test.py: error: argument tests: invalid choice: 'z' (choose from 'a', 'b', 'c', 'd', ['a', 'd'])
$ python test.py -h
usage: test.py [-h] [{a,b,c,d,['a', 'd']} ...]
positional arguments:
{a,b,c,d,['a', 'd']}
...
这可能是理想的,也可能不是理想的,这取决于用例,因为即使不混淆,输出看起来也很奇怪。如果这个输出是面向用户的,它可能并不理想,但如果这是为了维护一些不会泄露给用户的内部系统调用模拟,消息可能是不可见的,所以这可能是一个可以接受的解决方法。因此,如果生成的选择消息的清晰度至关重要(>99% 的典型用例),我不推荐这种方法。
但是,考虑到自定义操作被认为是不理想的,我假设覆盖 ArgumentParser
类可能是一个可能的选择,并且考虑到 _check_value
在 3.4 之间没有改变和 3.10,这可能代表消除不兼容检查的最少附加代码(根据问题指定用例):
class ArgumentParser(argparse.ArgumentParser):
def _check_value(self, action, value):
if value is action.default:
return
return super()._check_value(action, value)
这将确保在使用不适合要求的默认实现之前,默认值被视为有效选择(如果该值是操作的默认值,则返回 None
,否则返回默认检查)如问题中所述;请注意,这会阻止对 action.default
提供的有效内容进行更深入的检查(如果有必要,自定义 Action 类肯定是最佳选择)。
不妨展示自定义类的示例用法(即复制/粘贴原始代码,删除 argparse.
以使用新的自定义类):
parser = ArgumentParser()
parser.add_argument('tests', nargs='*', choices=['a', 'b', 'c', 'd'],
default=['a', 'd'])
args = parser.parse_args()
print(args.tests)
用法:
$ python test.py
['a', 'd']
$ python test.py a z
usage: test.py [-h] [{a,b,c,d} ...]
test.py: error: argument tests: invalid choice: 'z' (choose from 'a', 'b', 'c', 'd')
$ python test.py -h
usage: test.py [-h] [{a,b,c,d} ...]
positional arguments:
{a,b,c,d}
optional arguments:
-h, --help show this help message and exit
关于python - 有没有办法将 python argparse 与 nargs ='*' 、选项和默认值一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73396488/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!