Python Argparse可选布尔值

Python Argparse可选布尔值,python,python-3.x,argparse,Python,Python 3.x,Argparse,我试图获得以下行为: python test.py=>store foo=False python test.py--foo=>store foo=True python test.py--foo bool=>store foo=bool 当我使用 parser.add_argument('--foo',nargs='?', default=False, const=True) 但是,如果我添加type=bool,试图强制强制强制转换为布尔值,它就会中断。在这种情况下 python

我试图获得以下行为:

  • python test.py=>store foo=False
  • python test.py--foo=>store foo=True
  • python test.py--foo bool=>store foo=bool
当我使用

    parser.add_argument('--foo',nargs='?', default=False, const=True)
但是,如果我添加
type=bool
,试图强制强制强制转换为布尔值,它就会中断。在这种情况下

python test.py --foo False
实际上最终存储的是
foo=True
。发生了什么事???

您应该将参数改为布尔参数:

parser.add_argument('--foo', action='store_true')
因此,如果没有
--foo
选项:

python test.py
python test.py --foo
将导致
foo
参数的
False
值,并且存在
--foo
选项:

python test.py
python test.py --foo
将导致
foo
参数的
True
值。

您确定需要该模式吗
--foo
--foo
组合在一起,对于布尔开关来说,不是一种常用的模式

至于您的问题,请记住命令行值是一个字符串,
type=bool
表示您希望应用
bool(输入的字符串值)
。对于
——foo False
,这意味着
bool(“False”)
,产生
True
;所有非空字符串都为真!我也看到了

与其支持
--foo
/
--foo
,我强烈建议您使用
--foo
表示
,删除参数值,而是添加
--no foo
选项以显式设置

parser.add_argument('--foo', default=False, action='store_true')
parser.add_argument('--no-foo', dest='foo', action='store_false')
--no foo
开关上添加的
dest='foo'
确保它存储的
False
值(通过
store\u False
)最终位于相同的
args.foo
属性上

从Python 3.9开始,您还可以使用
argparse.BooleanOptionalAction
action类:

parser.add_argument("--foo", action=argparse.BooleanOptionalAction)
它将具有相同的效果,处理
--foo
--no foo
来设置和清除标志

如果您有一些其他配置机制将
foo
设置为
True
,并且需要使用命令行开关再次覆盖,那么您只需要一个
--foo/--no foo
组合
--no-
是一种广泛采用的标准,用于反转布尔命令行开关

如果您不需要使用
--no-foo
反向开关(因为省略
--foo
已经意味着“false”),那么只需使用
操作class='store\u true'
选项即可。这使您的命令行简单明了

但是,如果您的用例或其他约束特别要求您的命令行必须具有某种对
--foo(true | false | 0 | 1)
的支持,那么添加您自己的转换器:

def str_to_bool(value):
    if isinstance(value, bool):
        return value
    if value.lower() in {'false', 'f', '0', 'no', 'n'}:
        return False
    elif value.lower() in {'true', 't', '1', 'yes', 'y'}:
        return True
    raise ValueError(f'{value} is not a valid boolean value')

parser.add_argument('--foo', type=str_to_bool, nargs='?', const=True, default=False)
  • const
    值用于省略参数值的
    nargs='?'
    参数。在这里,当使用
    --foo
    时,设置
    foo=True
  • 当根本不使用开关时,将使用
    default=False
  • type=str\u to\u bool
    用于处理
    --foo
    案例
演示:


但这不允许使用
--foo bool
。这是不需要的。我已经用更好的解释更新了我的答案。当然,但是有指定禁用foo选项的用例,特别是在“来自多个源的合并配置,包括命令行”场景中<代码>--no foo是这里的常见选择。另外,我之所以要这样做,是因为我正在编写的是一个构建器文件,它编写了大量bash脚本并将它们提交给SLURM工作负载管理器。我提交的可选参数要经过一些预处理步骤,然后在SLURM脚本内的python调用中附加一组派生参数。现在,我发现实现这一点的最简单方法是拥有一个参数字典,我希望将其传递给SLURM脚本并附加所有键值对。现在根据您的建议,我必须检查是否手动设置了一个标志。@Hyperplane:您可以接受JSON编码的配置字符串吗?然后,如果
args.json\u config
是解码的json对象,那么您所要做的就是使用
args=parser.parse\u args()
args.update(args.json\u config)
@Hyperplane:
parser.add\u参数('--json config',type=json.loads)
应该足以定义这样一个开关。这听起来是一个非常好的解决方案。目前使用
type=string2bool
似乎已经足够了,但我会记住这个想法。再次感谢您的--no-pattern,argparse引入了BooleanOptionalAction