标签归档:argparse

在argparse中带有破折号的选项

问题:在argparse中带有破折号的选项

我想在argparse模块中有一些选项,例如,--pm-export当我尝试使用它时,就像args.pm-export出现没有属性的错误一样pm。我该如何解决这个问题?-命令行选项中可以有吗?

I want to have some options in argparse module such as --pm-export however when I try to use it like args.pm-export I get the error that there is not attribute pm. How can I get around this issue? Is it possible to have - in command line options?


回答 0

由于在指定的argparse文档

对于可选的参数操作,通常从选项字符串中推断出dest的值。ArgumentParser通过获取第一个long选项字符串并剥离初始--字符串来生成dest的值。任何内部-字符都将转换为_字符,以确保字符串是有效的属性名称

因此,您应该使用args.pm_export

As indicated in the argparse docs:

For optional argument actions, the value of dest is normally inferred from the option strings. ArgumentParser generates the value of dest by taking the first long option string and stripping away the initial -- string. Any internal - characters will be converted to _ characters to make sure the string is a valid attribute name

So you should be using args.pm_export.


回答 1

不幸的是,短划线到下划线的替换不适用于位置参数(不带前缀--),例如

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('logs-dir',
                    help='Directory with .log and .log.gz files')
parser.add_argument('results-csv', type=argparse.FileType('w'),
                    default=sys.stdout,
                    help='Output .csv filename')
args = parser.parse_args()
print args

# gives
# Namespace(logs-dir='./', results-csv=<open file 'lool.csv', mode 'w' at 0x9020650>)

因此,您应该使用第一个参数add_argument()作为属性名称,并使用metavarkwarg设置它在帮助中的外观:

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('logs_dir', metavar='logs-dir',
                    nargs=1,
                    help='Directory with .log and .log.gz files')
parser.add_argument('results_csv', metavar='results-csv',
                    nargs=1,
                    type=argparse.FileType('w'),
                    default=sys.stdout,
                    help='Output .csv filename')
args = parser.parse_args()
print args

# gives
# Namespace(logs_dir=['./'], results_csv=[<open file 'lool.csv', mode 'w' at 0xb71385f8>])

Unfortunately, dash-to-underscore replacement doesn’t work for positionalarguments (not prefixed by --) like

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('logs-dir',
                    help='Directory with .log and .log.gz files')
parser.add_argument('results-csv', type=argparse.FileType('w'),
                    default=sys.stdout,
                    help='Output .csv filename')
args = parser.parse_args()
print args

# gives
# Namespace(logs-dir='./', results-csv=<open file 'lool.csv', mode 'w' at 0x9020650>)

So, you should use 1’st argument to add_argument() as attribute name and metavar kwarg to set how it should look in help:

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('logs_dir', metavar='logs-dir',
                    nargs=1,
                    help='Directory with .log and .log.gz files')
parser.add_argument('results_csv', metavar='results-csv',
                    nargs=1,
                    type=argparse.FileType('w'),
                    default=sys.stdout,
                    help='Output .csv filename')
args = parser.parse_args()
print args

# gives
# Namespace(logs_dir=['./'], results_csv=[<open file 'lool.csv', mode 'w' at 0xb71385f8>])

回答 2

破折号转换为下划线:

import argparse
pa = argparse.ArgumentParser()
pa.add_argument('--foo-bar')
args = pa.parse_args(['--foo-bar', '24'])
print args # Namespace(foo_bar='24')

Dashes are converted to underscores:

import argparse
pa = argparse.ArgumentParser()
pa.add_argument('--foo-bar')
args = pa.parse_args(['--foo-bar', '24'])
print args # Namespace(foo_bar='24')

Python argparse忽略无法识别的参数

问题:Python argparse忽略无法识别的参数

Optparse,旧版本只是忽略所有无法识别的参数并继续执行。在大多数情况下,这不是理想的,已在argparse中进行了更改。但是在某些情况下,您想忽略任何无法识别的参数并解析您指定的参数。

例如:

parser = argparse.ArgumentParser()
parser.add_argument('--foo', dest="foo")
parser.parse_args()

$python myscript.py --foo 1 --bar 2
error: unrecognized arguments: --bar

反正有覆盖吗?

Optparse, the old version just ignores all unrecognised arguments and carries on. In most situations, this isn’t ideal and was changed in argparse. But there are a few situations where you want to ignore any unrecognised arguments and parse the ones you’ve specified.

For example:

parser = argparse.ArgumentParser()
parser.add_argument('--foo', dest="foo")
parser.parse_args()

$python myscript.py --foo 1 --bar 2
error: unrecognized arguments: --bar

Is there anyway to overwrite this?


回答 0

更换

args = parser.parse_args()

args, unknown = parser.parse_known_args()

例如,

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
args, unknown = parser.parse_known_args(['--foo', 'BAR', 'spam'])
print(args)
# Namespace(foo='BAR')
print(unknown)
# ['spam']

Replace

args = parser.parse_args()

with

args, unknown = parser.parse_known_args()

For example,

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
args, unknown = parser.parse_known_args(['--foo', 'BAR', 'spam'])
print(args)
# Namespace(foo='BAR')
print(unknown)
# ['spam']

回答 1

parser.add_argument('args', nargs=argparse.REMAINDER)如果要使用它们,可以将其余部分放入新的参数中。

You can puts the remaining parts into a new argument with parser.add_argument('args', nargs=argparse.REMAINDER) if you want to use them.


回答 2

实际上,argparse仍然“忽略” _unrecognized_args。只要这些“无法识别”的参数不使用默认前缀,您就不会听到解析器的任何抱怨。

parse.parse_args()如果要使用以下参数执行程序,请使用@anutbu的配置,但使用standard 。

$ program --foo BAR a b +cd e

我们将使用此具有命名空间的数据集合。

Namespace(_unrecognized_args=['a', 'b', '+cd', 'e'], foo='BAR')

如果我们想-忽略默认前缀,我们可以更改ArgumentParser并决定将+“ a” 用作我们的“可识别”参数。

parser = argparse.ArgumentParser(prefix_chars='+')
parser.add_argument('+cd')

相同的命令将产生

Namespace(_unrecognized_args=['--foo', 'BAR', 'a', 'b'], cd='e')

把它放到你的烟斗里然后抽烟=)

欢乐!

Actually argparse does still “ignore” _unrecognized_args. As long as these “unrecognized” arguments don’t use the default prefix you will hear no complaints from the parser.

Using @anutbu’s configuration but with the standard parse.parse_args(), if we were to execute our program with the following arguments.

$ program --foo BAR a b +cd e

We will have this Namespaced data collection to work with.

Namespace(_unrecognized_args=['a', 'b', '+cd', 'e'], foo='BAR')

If we wanted the default prefix - ignored we could change the ArgumentParser and decide we are going to use a + for our “recognized” arguments instead.

parser = argparse.ArgumentParser(prefix_chars='+')
parser.add_argument('+cd')

The same command will produce

Namespace(_unrecognized_args=['--foo', 'BAR', 'a', 'b'], cd='e')

Put that in your pipe and smoke it =)

nJoy!


需要使用argparse的两个参数之一

问题:需要使用argparse的两个参数之一

鉴于:

import argparse

pa = argparse.ArgumentParser()
pa.add_argument('--foo')
pa.add_argument('--bar')

print pa.parse_args('--foo 1'.split())

我如何

  • 将“ foo,bar”中的至少一项设为强制性:--foo x--bar y并且--foo x --bar y可以
  • 使“ foo,bar”中的一项至多为强制性的:--foo x或者--bar y很好,--foo x --bar y不是

Given:

import argparse

pa = argparse.ArgumentParser()
pa.add_argument('--foo')
pa.add_argument('--bar')

print pa.parse_args('--foo 1'.split())

how do I

  • make at least one of “foo, bar” mandatory: --foo x, --bar y and --foo x --bar y are fine
  • make at most one of “foo, bar” mandatory: --foo x or --bar y are fine, --foo x --bar y is not

回答 0

我认为您正在寻找类似互斥的内容(至少对于问题的第二部分而言)。

这样,仅foo或bar将被接受,而不是两者都被接受。

    import argparse

    parser = argparse.ArgumentParser()
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('--foo',action=.....)
    group.add_argument('--bar',action=.....)
    args = parser.parse_args()

顺便说一句,只是发现了另一个问题,指的是同样的问题。

希望这可以帮助

I think you are searching for something like mutual exclusion (at least for the second part of your question).

This way, only foo or bar will be accepted, not both.

    import argparse

    parser = argparse.ArgumentParser()
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('--foo',action=.....)
    group.add_argument('--bar',action=.....)
    args = parser.parse_args()

BTW, just found another question referring to the same kind of issue.

Hope this helps


回答 1

如果您需要模块未提供的某些检查,则可以始终手动进行:

pa = argparse.ArgumentParser()
...
args = pa.parse_args()

if args.foo is None and args.bar is None:
   pa.error("at least one of --foo and --bar required")

If you need some check that is not provided by the module you can always do it manually:

pa = argparse.ArgumentParser()
...
args = pa.parse_args()

if args.foo is None and args.bar is None:
   pa.error("at least one of --foo and --bar required")

Argparse:“可选参数”下列出了必需参数吗?

问题:Argparse:“可选参数”下列出了必需参数吗?

我使用下面的简单代码来解析一些参数。请注意,其中之一是必需的。不幸的是,当用户在不提供参数的情况下运行脚本时,显示的用法/帮助文本并不表示存在一个非可选的参数,我感到非常困惑。如何获取python以指示参数不是可选的?

这是代码:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Foo')
    parser.add_argument('-i','--input', help='Input file name', required=True)
    parser.add_argument('-o','--output', help='Output file name', default="stdout")
    args = parser.parse_args()
    print ("Input file: %s" % args.input )
    print ("Output file: %s" % args.output )

在不提供必需参数的情况下运行上述代码时,得到以下输出:

usage: foo.py [-h] -i INPUT [-o OUTPUT]

Foo

optional arguments:
    -h, --help            show this help message and exit
    -i INPUT, --input INPUT
                          Input file name
    -o OUTPUT, --output OUTPUT
                          Output file name

I use the following simple code to parse some arguments; note that one of them is required. Unfortunately, when the user runs the script without providing the argument, the displayed usage/help text does not indicate that there is a non-optional argument, which I find very confusing. How can I get python to indicate that an argument is not optional?

Here is the code:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Foo')
    parser.add_argument('-i','--input', help='Input file name', required=True)
    parser.add_argument('-o','--output', help='Output file name', default="stdout")
    args = parser.parse_args()
    print ("Input file: %s" % args.input )
    print ("Output file: %s" % args.output )

When running above code without providing the required argument, I get the following output:

usage: foo.py [-h] -i INPUT [-o OUTPUT]

Foo

optional arguments:
    -h, --help            show this help message and exit
    -i INPUT, --input INPUT
                          Input file name
    -o OUTPUT, --output OUTPUT
                          Output file name

回答 0

-或开头的参数--通常被认为是可选的。所有其他参数都是位置参数,因此是设计所必需的(例如位置函数自变量)。可能需要可选参数,但这有点违背其设计。由于它们仍然是非位置参数的一部分,因此即使需要它们,它们仍将列在令人困惑的标题“可选参数”下。但是,用法部分缺少的方括号表明确实需要它们。

另请参阅文档

通常,argparse模块假定-f和–bar之类的标志表示可选参数,在命令行中始终可以将其省略。

注意:必需的选项通常被认为是错误的格式,因为用户期望选项是可选的,因此应尽可能避免使用。

就是说,帮助中的标头“位置参数”“可选参数”是由两个参数组生成的,参数被自动分成两个。现在,您可以“破解”并更改可选参数的名称,但是一种更为优雅的解决方案是为“必需的命名参数”(或您要调用的任何参数)创建另一个组:

parser = argparse.ArgumentParser(description='Foo')
parser.add_argument('-o', '--output', help='Output file name', default='stdout')
requiredNamed = parser.add_argument_group('required named arguments')
requiredNamed.add_argument('-i', '--input', help='Input file name', required=True)
parser.parse_args(['-h'])
usage: [-h] [-o OUTPUT] -i INPUT

Foo

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output file name

required named arguments:
  -i INPUT, --input INPUT
                        Input file name

Parameters starting with - or -- are usually considered optional. All other parameters are positional parameters and as such required by design (like positional function arguments). It is possible to require optional arguments, but this is a bit against their design. Since they are still part of the non-positional arguments, they will still be listed under the confusing header “optional arguments” even if they are required. The missing square brackets in the usage part however show that they are indeed required.

See also the documentation:

In general, the argparse module assumes that flags like -f and –bar indicate optional arguments, which can always be omitted at the command line.

Note: Required options are generally considered bad form because users expect options to be optional, and thus they should be avoided when possible.

That being said, the headers “positional arguments” and “optional arguments” in the help are generated by two argument groups in which the arguments are automatically separated into. Now, you could “hack into it” and change the name of the optional ones, but a far more elegant solution would be to create another group for “required named arguments” (or whatever you want to call them):

parser = argparse.ArgumentParser(description='Foo')
parser.add_argument('-o', '--output', help='Output file name', default='stdout')
requiredNamed = parser.add_argument_group('required named arguments')
requiredNamed.add_argument('-i', '--input', help='Input file name', required=True)
parser.parse_args(['-h'])
usage: [-h] [-o OUTPUT] -i INPUT

Foo

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output file name

required named arguments:
  -i INPUT, --input INPUT
                        Input file name

回答 1

由于我倾向于在可选参数之前列出必需的参数,因此我通过以下方法解决了这个问题:

    parser = argparse.ArgumentParser()
    parser._action_groups.pop()
    required = parser.add_argument_group('required arguments')
    optional = parser.add_argument_group('optional arguments')
    required.add_argument('--required_arg', required=True)
    optional.add_argument('--optional_arg')
    return parser.parse_args()

并输出:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
               [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  --optional_arg OPTIONAL_ARG

我可以在可选参数组中不显示“帮助”的情况下生活。

Since I prefer to list required arguments before optional, I hack around it via:

    parser = argparse.ArgumentParser()
    parser._action_groups.pop()
    required = parser.add_argument_group('required arguments')
    optional = parser.add_argument_group('optional arguments')
    required.add_argument('--required_arg', required=True)
    optional.add_argument('--optional_arg')
    return parser.parse_args()

and this outputs:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
               [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  --optional_arg OPTIONAL_ARG

I can live without ‘help’ showing up in the optional arguments group.


回答 2

从@Karl Rosaen建造

parser = argparse.ArgumentParser()
optional = parser._action_groups.pop() # Edited this line
required = parser.add_argument_group('required arguments')
# remove this line: optional = parser...
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')
parser._action_groups.append(optional) # added this line
return parser.parse_args()

并输出:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

Building off of @Karl Rosaen

parser = argparse.ArgumentParser()
optional = parser._action_groups.pop() # Edited this line
required = parser.add_argument_group('required arguments')
# remove this line: optional = parser...
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')
parser._action_groups.append(optional) # added this line
return parser.parse_args()

and this outputs:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

回答 3

再过一次,以@RalphyZ为基础

这个不会破坏公开的API。

from argparse import ArgumentParser, SUPPRESS
# Disable default help
parser = ArgumentParser(add_help=False)
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')

# Add back help 
optional.add_argument(
    '-h',
    '--help',
    action='help',
    default=SUPPRESS,
    help='show this help message and exit'
)
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')

它将显示与上面相同的内容,并且应该在将来的版本中保留下来:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

One more time, building off of @RalphyZ

This one doesn’t break the exposed API.

from argparse import ArgumentParser, SUPPRESS
# Disable default help
parser = ArgumentParser(add_help=False)
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')

# Add back help 
optional.add_argument(
    '-h',
    '--help',
    action='help',
    default=SUPPRESS,
    help='show this help message and exit'
)
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')

Which will show the same as above and should survive future versions:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

在不带任何参数的情况下调用脚本时,使用python argparse显示帮助消息

问题:在不带任何参数的情况下调用脚本时,使用python argparse显示帮助消息

这可能很简单。假设我有一个使用argparse处理命令行参数/选项的程序。以下将打印“帮助”消息:

./myprogram -h

要么:

./myprogram --help

但是,如果我运行脚本时不带任何参数,则它不会执行任何操作。我要它做的是在不带参数的情况下显示用法消息。怎么做?

This might be a simple one. Assume I have a program that uses argparse to process command line arguments/options. The following will print the ‘help’ message:

./myprogram -h

or:

./myprogram --help

But, if I run the script without any arguments whatsoever, it doesn’t do anything. What I want it to do is to display the usage message when it is called with no arguments. How is that done?


回答 0

这个答案来自Google网上论坛的Steven Bethard 。我将其重新发布在这里,以方便没有Google帐户的人访问。

您可以覆盖方法的默认行为error

import argparse
import sys

class MyParser(argparse.ArgumentParser):
    def error(self, message):
        sys.stderr.write('error: %s\n' % message)
        self.print_help()
        sys.exit(2)

parser = MyParser()
parser.add_argument('foo', nargs='+')
args = parser.parse_args()

请注意,上述解决方案将在error 触发方法时打印帮助消息。例如,test.py --blah如果--blah不是有效的选项,还将打印帮助消息。

如果只在命令行中未提供任何参数的情况下才打印帮助消息,那么也许这仍然是最简单的方法:

import argparse
import sys

parser=argparse.ArgumentParser()
parser.add_argument('foo', nargs='+')
if len(sys.argv)==1:
    parser.print_help(sys.stderr)
    sys.exit(1)
args=parser.parse_args()

请注意,parser.print_help()默认情况下会打印到标准输出。正如init_js建议的那样,用于parser.print_help(sys.stderr)打印到stderr。

This answer comes from Steven Bethard on Google groups. I’m reposting it here to make it easier for people without a Google account to access.

You can override the default behavior of the error method:

import argparse
import sys

class MyParser(argparse.ArgumentParser):
    def error(self, message):
        sys.stderr.write('error: %s\n' % message)
        self.print_help()
        sys.exit(2)

parser = MyParser()
parser.add_argument('foo', nargs='+')
args = parser.parse_args()

Note that the above solution will print the help message whenever the error method is triggered. For example, test.py --blah will print the help message too if --blah isn’t a valid option.

If you want to print the help message only if no arguments are supplied on the command line, then perhaps this is still the easiest way:

import argparse
import sys

parser=argparse.ArgumentParser()
parser.add_argument('foo', nargs='+')
if len(sys.argv)==1:
    parser.print_help(sys.stderr)
    sys.exit(1)
args=parser.parse_args()

Note that parser.print_help() prints to stdout by default. As init_js suggests, use parser.print_help(sys.stderr) to print to stderr.


回答 1

除了编写类,可以使用try / except代替

try:
    options = parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

好处是工作流程更加清晰,您不需要存根类。不利的一面是第一行“用法”行被打印两次。

这将至少需要一个强制性参数。没有强制性参数,在命令行上提供零args是有效的。

Instead of writing a class, a try/except can be used instead

try:
    options = parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

The upside is that the workflow is clearer and you don’t need a stub class. The downside is that the first ‘usage’ line is printed twice.

This will need at least one mandatory argument. With no mandatory arguments, providing zero args on the commandline is valid.


回答 2

使用argparse,您可以执行以下操作:

parser.argparse.ArgumentParser()
#parser.add_args here

#sys.argv includes a list of elements starting with the program
if len(sys.argv) < 2:
    parser.print_usage()
    sys.exit(1)

With argparse you could do:

parser.argparse.ArgumentParser()
#parser.add_args here

#sys.argv includes a list of elements starting with the program
if len(sys.argv) < 2:
    parser.print_usage()
    sys.exit(1)

回答 3

如果必须为运行脚本指定参数,请对ArgumentParser 使用必需的参数,如下所示:-

parser.add_argument('--foo', required=True)

如果脚本不带任何参数运行,parse_args()将报告错误。

If you have arguments that must be specified for the script to run – use the required parameter for ArgumentParser as shown below:-

parser.add_argument('--foo', required=True)

parse_args() will report an error if the script is run without any arguments.


回答 4

如果您为(子)解析器关联了默认功能,如所述add_subparsers,您可以简单地将其添加为默认操作:

parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)

如果由于缺少位置参数而引发异常,请添加try-except。

If you associate default functions for (sub)parsers, as is mentioned under add_subparsers, you can simply add it as the default action:

parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)

Add the try-except if you raise exceptions due to missing positional arguments.


回答 5

最干净的解决方案是,如果在命令行中未提供默认参数,则手动传递默认参数:

parser.parse_args(args=None if sys.argv[1:] else ['--help'])

完整的例子:

import argparse, sys

parser = argparse.ArgumentParser()
parser.add_argument('--host', default='localhost', help='Host to connect to')
# parse arguments
args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])

# use your args
print("connecting to {}".format(args.host))

如果不带参数调用,这将打印出完整的帮助(不是简短用法)。

The cleanest solution will be to manually pass default argument if none were given on the command line:

parser.parse_args(args=None if sys.argv[1:] else ['--help'])

Complete example:

import argparse, sys

parser = argparse.ArgumentParser()
parser.add_argument('--host', default='localhost', help='Host to connect to')
# parse arguments
args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])

# use your args
print("connecting to {}".format(args.host))

This will print complete help (not short usage) if called w/o arguments.


回答 6

将我的版本扔到这里:

import argparse

parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
    parser.print_help()
    parser.exit(1)

您可能会注意到parser.exit-我主要是这样做的,因为如果这是sys文件中唯一的原因,它会保存导入行…

Throwing my version into the pile here:

import argparse

parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
    parser.print_help()
    parser.exit(1)

You may notice the parser.exit – I mainly do it like that because it saves an import line if that was the only reason for sys in the file…


回答 7

有一对可以完成这项工作的单行代码sys.argv[1:](这是一个非常常见的Python习惯用法,用于引用命令行参数,sys.argv[0]即脚本的名称)。

第一个是不言自明的,干净的和pythonic的:

args = parser.parse_args(None if sys.argv[1:] else ['-h'])

第二个是一个小黑客。结合先前评估的事实,即空列表FalseTrue == 1False == 0等价物,您将获得以下信息:

args = parser.parse_args([None, ['-h']][not sys.argv[1:]])

也许括号太多,但很清楚是否选择了先前的参数。

_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])

There are a pair of one-liners with sys.argv[1:] (a very common Python’s idiom to refer the command line arguments, being sys.argv[0] the script’s name) that can do the job.

The first one is self-explanatory, clean and pythonic:

args = parser.parse_args(None if sys.argv[1:] else ['-h'])

The second one is a little hackier. Combining the previously evaluated fact that an empty list is False with the True == 1 and False == 0 equivalences you get this:

args = parser.parse_args([None, ['-h']][not sys.argv[1:]])

Maybe too many brackets, but pretty clear if a previous argument selection was made.

_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])

回答 8

parser.print_help()
parser.exit()

parser.exit方法还接受status(返回码)和message值(您自己包括尾随换行符!)。

一个有思想的例子,:)

#!/usr/bin/env python3

""" Example argparser based python file
"""

import argparse

ARGP = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawTextHelpFormatter,
)
ARGP.add_argument('--example', action='store_true', help='Example Argument')


def main(argp=None):
    if argp is None:
        argp = ARGP.parse_args()  # pragma: no cover

    if 'soemthing_went_wrong' and not argp.example:
        ARGP.print_help()
        ARGP.exit(status=128, message="\nI just don't know what went wrong, maybe missing --example condition?\n")


if __name__ == '__main__':
    main()  # pragma: no cover

示例调用:

$ python3〜/ helloworld.py; 回声$?
用法:helloworld.py [-h] [--example]

 示例基于argparser的python文件

可选参数:
  -h,--help显示此帮助消息并退出
  --example示例参数

我只是不知道出了什么问题,也许会丢失-示例条件?
128
$ python3〜/ helloworld.py-示例; 回声$?
0
parser.print_help()
parser.exit()

The parser.exit method also accept a status (returncode), and a message value (include a trailing newline yourself!).

an opinionated example, :)

#!/usr/bin/env python3

""" Example argparser based python file
"""

import argparse

ARGP = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawTextHelpFormatter,
)
ARGP.add_argument('--example', action='store_true', help='Example Argument')


def main(argp=None):
    if argp is None:
        argp = ARGP.parse_args()  # pragma: no cover

    if 'soemthing_went_wrong' and not argp.example:
        ARGP.print_help()
        ARGP.exit(status=64, message="\nSomething went wrong, --example condition was not set\n")


if __name__ == '__main__':
    main()  # pragma: no cover

Example calls:

$ python3 ~/helloworld.py; echo $?
usage: helloworld.py [-h] [--example]

 Example argparser based python file

optional arguments:
  -h, --help  show this help message and exit
  --example   Example Argument

Something went wrong, --example condition was not set
64
$ python3 ~/helloworld.py --example; echo $?
0

回答 9

使用nargs设置位置参数,并检查位置args是否为空。

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
    parser.print_help()

参考Python nargs

Set your positional arguments with nargs, and check if positional args are empty.

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
    parser.print_help()

Reference Python nargs


回答 10

这是另一种实现方法,如果您需要一些灵活的方法,如果传递了特定的参数,则希望在显示帮助的地方显示帮助,则完全没有或超过1个冲突的arg:

import argparse
import sys

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--days', required=False,  help="Check mapped inventory that is x days old", default=None)
    parser.add_argument('-e', '--event', required=False, action="store", dest="event_id",
                        help="Check mapped inventory for a specific event", default=None)
    parser.add_argument('-b', '--broker', required=False, action="store", dest="broker_id",
                        help="Check mapped inventory for a broker", default=None)
    parser.add_argument('-k', '--keyword', required=False, action="store", dest="event_keyword",
                        help="Check mapped inventory for a specific event keyword", default=None)
    parser.add_argument('-p', '--product', required=False, action="store", dest="product_id",
                        help="Check mapped inventory for a specific product", default=None)
    parser.add_argument('-m', '--metadata', required=False, action="store", dest="metadata",
                        help="Check mapped inventory for specific metadata, good for debugging past tix", default=None)
    parser.add_argument('-u', '--update', required=False, action="store_true", dest="make_updates",
                        help="Update the event for a product if there is a difference, default No", default=False)
    args = parser.parse_args()

    days = args.days
    event_id = args.event_id
    broker_id = args.broker_id
    event_keyword = args.event_keyword
    product_id = args.product_id
    metadata = args.metadata
    make_updates = args.make_updates

    no_change_counter = 0
    change_counter = 0

    req_arg = bool(days) + bool(event_id) + bool(broker_id) + bool(product_id) + bool(event_keyword) + bool(metadata)
    if not req_arg:
        print("Need to specify days, broker id, event id, event keyword or past tickets full metadata")
        parser.print_help()
        sys.exit()
    elif req_arg != 1:
        print("More than one option specified. Need to specify only one required option")
        parser.print_help()
        sys.exit()

    # Processing logic here ...

干杯!

Here is another way to do it, if you need something flexible where you want to display help if specific params are passed, none at all or more than 1 conflicting arg:

import argparse
import sys

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--days', required=False,  help="Check mapped inventory that is x days old", default=None)
    parser.add_argument('-e', '--event', required=False, action="store", dest="event_id",
                        help="Check mapped inventory for a specific event", default=None)
    parser.add_argument('-b', '--broker', required=False, action="store", dest="broker_id",
                        help="Check mapped inventory for a broker", default=None)
    parser.add_argument('-k', '--keyword', required=False, action="store", dest="event_keyword",
                        help="Check mapped inventory for a specific event keyword", default=None)
    parser.add_argument('-p', '--product', required=False, action="store", dest="product_id",
                        help="Check mapped inventory for a specific product", default=None)
    parser.add_argument('-m', '--metadata', required=False, action="store", dest="metadata",
                        help="Check mapped inventory for specific metadata, good for debugging past tix", default=None)
    parser.add_argument('-u', '--update', required=False, action="store_true", dest="make_updates",
                        help="Update the event for a product if there is a difference, default No", default=False)
    args = parser.parse_args()

    days = args.days
    event_id = args.event_id
    broker_id = args.broker_id
    event_keyword = args.event_keyword
    product_id = args.product_id
    metadata = args.metadata
    make_updates = args.make_updates

    no_change_counter = 0
    change_counter = 0

    req_arg = bool(days) + bool(event_id) + bool(broker_id) + bool(product_id) + bool(event_keyword) + bool(metadata)
    if not req_arg:
        print("Need to specify days, broker id, event id, event keyword or past tickets full metadata")
        parser.print_help()
        sys.exit()
    elif req_arg != 1:
        print("More than one option specified. Need to specify only one required option")
        parser.print_help()
        sys.exit()

    # Processing logic here ...

Cheers!


回答 11

如果您的命令是用户需要选择某些操作的命令,则使用具有required = True的互斥组。

这是对pd321给出的答案的扩展。

import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--batch", action='store', type=int,  metavar='pay_id')
group.add_argument("--list", action='store_true')
group.add_argument("--all", action='store_true', help='check all payments')

args=parser.parse_args()

if args.batch:
    print('batch {}'.format(args.batch))

if args.list:
    print('list')

if args.all:
    print('all')

输出:

$ python3 a_test.py
用法:a_test.py [-h](–batch pay_id | –list | –all)
a_test.py:错误:–batch –list –all参数之一是必需的

这仅提供基本帮助。其他一些答案将为您提供完整的帮助。但是至少您的用户知道他们可以做到-h

If your command is something where a user needs to choose some action, then use a mutually exclusive group with required=True.

This is kind of an extension to the answer given by pd321.

import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--batch", action='store', type=int,  metavar='pay_id')
group.add_argument("--list", action='store_true')
group.add_argument("--all", action='store_true', help='check all payments')

args=parser.parse_args()

if args.batch:
    print('batch {}'.format(args.batch))

if args.list:
    print('list')

if args.all:
    print('all')

Output:

$ python3 a_test.py
usage: a_test.py [-h] (–batch pay_id | –list | –all)
a_test.py: error: one of the arguments –batch –list –all is required

This only give the basic help. And some of the other answers will give you the full help. But at least your users know they can do -h


回答 12

这不好(也因为拦截了所有错误),但是:

def _error(parser):
    def wrapper(interceptor):
        parser.print_help()

        sys.exit(-1)

    return wrapper

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error(parser)

    parser.add_argument(...)
    ...

这是该类error功能的定义ArgumentParser

https://github.com/python/cpython/blob/276eb67c29d05a93fbc22eea5470282e73700d20/Lib/argparse.py#L2374

。如您所见,签名后需要两个参数。但是,类外部的函数对第一个参数一无所知:self,因为,大致来说,这是该类的参数。(我知道,你知道…)因此,只是通过自己selfmessage_error(...)不能(

def _error(self, message):
    self.print_help()

    sys.exit(-1)

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error
    ...
...

将输出:

...
"AttributeError: 'str' object has no attribute 'print_help'"

)。您可以通过调用函数来传递parserself_error

def _error(self, message):
    self.print_help()

    sys.exit(-1)

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error(parser)
    ...
...

,但您现在不想退出程序。然后返回它:

def _error(parser):
    def wrapper():
        parser.print_help()

        sys.exit(-1)

    return wrapper
...

。但是,parser不知道它是否已被修改,因此当发生错误时,它将发送原因(顺便说一下,其本地化翻译)。好吧,然后拦截它:

def _error(parser):
    def wrapper(interceptor):
        parser.print_help()

        sys.exit(-1)

    return wrapper
...

。现在,当发生错误并parser发送错误原因时,您将拦截它,看着它,然后……抛出。

This isn’t good (also, because intercepts all errors), but:

def _error(parser):
    def wrapper(interceptor):
        parser.print_help()

        sys.exit(-1)

    return wrapper

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error(parser)

    parser.add_argument(...)
    ...

Here is definition of the error function of the ArgumentParser class:

https://github.com/python/cpython/blob/276eb67c29d05a93fbc22eea5470282e73700d20/Lib/argparse.py#L2374

. As you see, following signature, it takes two arguments. However, functions outside the class nothing knows about first argument: self, because, roughly speaking, this is parameter for the class. (I know, that you know…) Thereby, just pass own self and message in _error(...) can’t (

def _error(self, message):
    self.print_help()

    sys.exit(-1)

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error
    ...
...

will output:

...
"AttributeError: 'str' object has no attribute 'print_help'"

). You can pass parser (self) in _error function, by calling it:

def _error(self, message):
    self.print_help()

    sys.exit(-1)

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error(parser)
    ...
...

, but you don’t want exit the program, right now. Then return it:

def _error(parser):
    def wrapper():
        parser.print_help()

        sys.exit(-1)

    return wrapper
...

. Nonetheless, parser doesn’t know, that it has been modified, thus when an error occurs, it will send cause of it (by the way, its localized translation). Well, then intercept it:

def _error(parser):
    def wrapper(interceptor):
        parser.print_help()

        sys.exit(-1)

    return wrapper
...

. Now, when error occurs and parser will send cause of it, you’ll intercept it, look at this, and… throw out.


Argparse:在“ –help”中包含默认值的方法吗?

问题:Argparse:在“ –help”中包含默认值的方法吗?

假设我有以下argparse代码段:

diags.cmdln_parser.add_argument( '--scan-time',
                     action  = 'store',
                     nargs   = '?',
                     type    = int,
                     default = 5,
                     help    = "Wait SCAN-TIME seconds between status checks.")

当前,--help返回:

usage: connection_check.py [-h]
                             [--version] [--scan-time [SCAN_TIME]]

          Test the reliability/uptime of a connection.



optional arguments:
-h, --help            show this help message and exit
--version             show program's version number and exit
--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.

我更喜欢这样的东西:

--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.
                    (Default = 5)

偷看帮助格式化程序代码,发现选择有限。是否有一种巧妙的方法来argparse--scan-time类似的方式打印默认值,还是我应该只是help格式化程序的子类?

Suppose I have the following argparse snippet:

diags.cmdln_parser.add_argument( '--scan-time',
                     action  = 'store',
                     nargs   = '?',
                     type    = int,
                     default = 5,
                     help    = "Wait SCAN-TIME seconds between status checks.")

Currently, --help returns:

usage: connection_check.py [-h]
                             [--version] [--scan-time [SCAN_TIME]]

          Test the reliability/uptime of a connection.



optional arguments:
-h, --help            show this help message and exit
--version             show program's version number and exit
--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.

I would prefer something like:

--scan-time [SCAN_TIME]
                    Wait SCAN-TIME seconds between status checks.
                    (Default = 5)

Peeking at the help formatter code revealed limited options. Is there a clever way to get argparse to print the default value for --scan-time in a similar fashion, or should I just subclass the help formatter?


回答 0

使用argparse.ArgumentDefaultsHelpFormatter格式化程序

parser = argparse.ArgumentParser(
    # ... other options ...
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

引用文档:

另一个可用的格式化程序类ArgumentDefaultsHelpFormatter,将添加有关每个参数的默认值的信息。

请注意,这仅适用于已定义帮助文本的参数;如果没有help参数值,则没有帮助消息将有关默认值的信息添加到中

然后,您的扫描时间选项的确切输出将变为:

  --scan-time [SCAN_TIME]
                        Wait SCAN-TIME seconds between status checks.
                        (default: 5)

Use the argparse.ArgumentDefaultsHelpFormatter formatter:

parser = argparse.ArgumentParser(
    # ... other options ...
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

To quote the documentation:

The other formatter class available, ArgumentDefaultsHelpFormatter, will add information about the default value of each of the arguments.

Note that this only applies to arguments that have help text defined; with no help value for an argument, there is no help message to add information about the default value to.

The exact output for your scan-time option then becomes:

  --scan-time [SCAN_TIME]
                        Wait SCAN-TIME seconds between status checks.
                        (default: 5)

回答 1

添加'%(default)s'到帮助参数以控制显示内容。

parser.add_argument("--type", default="toto", choices=["toto","titi"],
                              help = "type (default: %(default)s)")

Add '%(default)s' to the help parameter to control what is displayed.

parser.add_argument("--type", default="toto", choices=["toto","titi"],
                              help = "type (default: %(default)s)")

回答 2

包装类

这是迄今为止我发现的最可靠,最干的方法,既可以显示默认值,也可以同时使用另一个格式化程序argparse.RawTextHelpFormatter

#!/usr/bin/env python3

import argparse

class ArgumentParserWithDefaults(argparse.ArgumentParser):
    def add_argument(self, *args, help=None, default=None, **kwargs):
        if help is not None:
            kwargs['help'] = help
        if default is not None and args[0] != '-h':
            kwargs['default'] = default
            if help is not None:
                kwargs['help'] += ' Default: {}'.format(default)
        super().add_argument(*args, **kwargs)

parser = ArgumentParserWithDefaults(
    formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.add_argument('--no-default', help='''my help
for no-default''')
parser.add_argument('--no-help', default=101)

parser.print_help()
print()
print(parser.parse_args())

输出:

usage: main.py [-h] [-a A] [-b B] [--no-default NO_DEFAULT]
               [--no-help NO_HELP]

optional arguments:
  -h, --help            show this help message and exit
  -a A                  my help
                        for a Default: 13
  -b B                  my help
                        for b Default: 42
  --no-default NO_DEFAULT
                        my help
                        for no-default
  --no-help NO_HELP

Namespace(a=13, b=42, no_default=None, no_help=101)

ArgumentDefaultsHelpFormatter+ RawTextHelpFormatter多重继承

多重继承可以正常工作,但它似乎不是公共API:

#!/usr/bin/env python3

import argparse

class RawTextArgumentDefaultsHelpFormatter(
        argparse.ArgumentDefaultsHelpFormatter,
        argparse.RawTextHelpFormatter
    ):
        pass

parser = argparse.ArgumentParser(
    formatter_class=RawTextArgumentDefaultsHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.print_help()

输出:

usage: a.py [-h] [-a A] [-b B]

optional arguments:
  -h, --help  show this help message and exit
  -a A        my help
              for a (default: 13)
  -b B        my help
              for b (default: 42)

它之所以有效,是因为我们可以从https://github.com/python/cpython/blob/v3.6.5/Lib/argparse.py#L648的源代码中轻松地看到:

  • RawTextHelpFormatter 实施 _split_lines
  • ArgumentDefaultsHelpFormatter 实施 _get_help_string

因此我们可以猜测它们会一起正常工作。

但是,这似乎不是公共API,也不是的方法formatter_class,因此我认为目前尚无公共API方法。argparsedocstring说:

本模块中的所有其他类均视为实现细节。(还要注意,仅将HelpFormatter和RawDescriptionHelpFormatter视为对象名称是公共的-格式化程序对象的API仍被视为实现细节。)

另请参阅:自定义argparse帮助消息

在Python 3.6.5上测试。

Wrapper class

This is the most reliable and DRY approach I’ve found so far to both show defaults and use another formatter such as argparse.RawTextHelpFormatter at the same time:

#!/usr/bin/env python3

import argparse

class ArgumentParserWithDefaults(argparse.ArgumentParser):
    def add_argument(self, *args, help=None, default=None, **kwargs):
        if help is not None:
            kwargs['help'] = help
        if default is not None and args[0] != '-h':
            kwargs['default'] = default
            if help is not None:
                kwargs['help'] += ' Default: {}'.format(default)
        super().add_argument(*args, **kwargs)

parser = ArgumentParserWithDefaults(
    formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.add_argument('--no-default', help='''my help
for no-default''')
parser.add_argument('--no-help', default=101)

parser.print_help()
print()
print(parser.parse_args())

Output:

usage: main.py [-h] [-a A] [-b B] [--no-default NO_DEFAULT]
               [--no-help NO_HELP]

optional arguments:
  -h, --help            show this help message and exit
  -a A                  my help
                        for a Default: 13
  -b B                  my help
                        for b Default: 42
  --no-default NO_DEFAULT
                        my help
                        for no-default
  --no-help NO_HELP

Namespace(a=13, b=42, no_default=None, no_help=101)

ArgumentDefaultsHelpFormatter + RawTextHelpFormatter multiple inheritance

Multiple inheritance just works, but it does not seem to be public API:

#!/usr/bin/env python3

import argparse

class RawTextArgumentDefaultsHelpFormatter(
        argparse.ArgumentDefaultsHelpFormatter,
        argparse.RawTextHelpFormatter
    ):
        pass

parser = argparse.ArgumentParser(
    formatter_class=RawTextArgumentDefaultsHelpFormatter
)
parser.add_argument('-a', default=13, help='''my help
for a''')
parser.add_argument('-b', default=42, help='''my help
for b''')
parser.print_help()

Output:

usage: a.py [-h] [-a A] [-b B]

optional arguments:
  -h, --help  show this help message and exit
  -a A        my help
              for a (default: 13)
  -b B        my help
              for b (default: 42)

It just works works because as we can see trivially from the sources https://github.com/python/cpython/blob/v3.6.5/Lib/argparse.py#L648 that:

  • RawTextHelpFormatter implements _split_lines
  • ArgumentDefaultsHelpFormatter implements _get_help_string

so we can guess that they will work together just fine.

However, this does not seem to be public API, and neither are the methods of formatter_class, so I don’t think there is a public API way to do it currently. argparse docstring says:

All other classes in this module are considered implementation details. (Also note that HelpFormatter and RawDescriptionHelpFormatter are only considered public as object names — the API of the formatter objects is still considered an implementation detail.)

See also: Customize argparse help message

Tested on Python 3.6.5.


为什么要使用argparse而不是optparse?

问题:为什么要使用argparse而不是optparse?

我注意到Python 2.7文档还包含另一个命令行解析模块。除了getoptoptparse我们现在有argparse

为什么还要创建另一个命令行解析模块?为什么要使用它代替optparse?我应该了解一些新功能吗?

I noticed that the Python 2.7 documentation includes yet another command-line parsing module. In addition to getopt and optparse we now have argparse.

Why has yet another command-line parsing module been created? Why should I use it instead of optparse? Are there new features that I should know about?


回答 0

从python开始2.7optparse已弃用,希望将来会消失。

argparse由于其原始页面(https://code.google.com/archive/p/argparse/)上列出的所有原因而更好:

  • 处理位置参数
  • 支持子命令
  • 允许其他可选前缀,例如+/
  • 处理零个或多个和一个或多个样式参数
  • 产生更多有用的使用信息
  • 为自定义类型和操作提供更简单的界面

PEP 389中也提供了更多信息,它是将argparse其纳入标准库的工具。

As of python 2.7, optparse is deprecated, and will hopefully go away in the future.

argparse is better for all the reasons listed on its original page (https://code.google.com/archive/p/argparse/):

  • handling positional arguments
  • supporting sub-commands
  • allowing alternative option prefixes like + and /
  • handling zero-or-more and one-or-more style arguments
  • producing more informative usage messages
  • providing a much simpler interface for custom types and actions

More information is also in PEP 389, which is the vehicle by which argparse made it into the standard library.


回答 1

为什么要使用它代替optparse?是我应该知道的新功能吗?

我认为,@ Nicholas的答案可以很好地解决这一问题,但您不能从以下的“元”问题开始:

为什么还要创建另一个命令行解析模块?

将任何有用的模块添加到标准库中时,这就是两难的境地:当出现一种提供更好的,但向后不兼容的,提供相同功能的方法时,您该怎么办?

您要么坚持旧的,公认的超越方式(通常在谈论复杂的软件包时:异步,扭曲,tkinter,wx或Qt等),要么最终以多种不兼容的方式完成同一件事(XML与命令行解析器相比,恕我直言的解析器是一个更好的例子-但email与处理类似问题的无数旧方法相比,程序包和它们之间的距离也不远;-)。

您可能会在文档中对过时的“过时”方式进行抱怨,但是(只要需要保持向后兼容性)就不能真正消除它们,而必须停止大型的重要应用程序迁移到较新的Python版本。

(第二个难题,与您的问题没有直接关系,总结成一句老话:“标准库是好的软件包将要消亡的地方……”每年约有一半的版本发布,但不是非常好的软件包,非常稳定,不需要经常发布的版本,实际上可能会因为在标准库中被“冻结”而遭受严重损失……但这确实是一个不同的问题)。

Why should I use it instead of optparse? Are their new features I should know about?

@Nicholas’s answer covers this well, I think, but not the more “meta” question you start with:

Why has yet another command-line parsing module been created?

That’s the dilemma number one when any useful module is added to the standard library: what do you do when a substantially better, but backwards-incompatible, way to provide the same kind of functionality emerges?

Either you stick with the old and admittedly surpassed way (typically when we’re talking about complicated packages: asyncore vs twisted, tkinter vs wx or Qt, …) or you end up with multiple incompatible ways to do the same thing (XML parsers, IMHO, are an even better example of this than command-line parsers — but the email package vs the myriad old ways to deal with similar issues isn’t too far away either;-).

You may make threatening grumbles in the docs about the old ways being “deprecated”, but (as long as you need to keep backwards compatibility) you can’t really take them away without stopping large, important applications from moving to newer Python releases.

(Dilemma number two, not directly related to your question, is summarized in the old saying “the standard library is where good packages go to die”… with releases every year and a half or so, packages that aren’t very, very stable, not needing releases any more often than that, can actually suffer substantially by being “frozen” in the standard library… but, that’s really a different issue).


回答 2

添加Python原理的最佳来源是其PEP: PEP 389:argparse-新的命令行解析模块,尤其是标题为“ 为什么getopt和optparse不够?”的部分。

The best source for rationale for a Python addition would be its PEP: PEP 389: argparse – New Command Line Parsing Module, in particular, the section entitled, Why aren’t getopt and optparse enough?


回答 3

街上也有新孩子!

  • 除了已经提到的过时的optparse。[不使用]
  • argparse还提到了,这是不愿意包含外部库的人们的解决方案。
  • docopt是值得研究的外部库,它使用文档字符串作为输入的解析器。
  • click也是外部库,并使用修饰符定义参数。(我的来源建议:为什么单击
  • python-inquirer用于选择工具,基于Inquirer.js(repo

如果你需要一个更深入的比较,请阅读,你可能最终使用docopt点击。感谢Kyle Purdon!

There are also new kids on the block!

  • Besides the already mentioned deprecated optparse. [DO NOT USE]
  • argparse was also mentioned, which is a solution for people not willing to include external libs.
  • docopt is an external lib worth looking at, which uses a documentation string as the parser for your input.
  • click is also external lib and uses decorators for defining arguments. (My source recommends: Why Click)
  • python-inquirer For selection focused tools and based on Inquirer.js (repo)

If you need a more in-depth comparison please read this and you may end up using docopt or click. Thanks to Kyle Purdon!


回答 4

起初,我像@fmark一样不愿意从optparse切换到argparse,因为:

  1. 我以为差异不是很大。
  2. 默认情况下,相当多的VPS仍提供Python 2.6。

然后我看到了这个文档,argparse胜过optparse,尤其是在谈论生成有意义的帮助消息时: http //argparse.googlecode.com/svn/trunk/doc/argparse-vs-optparse.html

然后我看到@Nicholas的“ argparse vs. optparse ”,说我们可以在python <2.7中使用argparse(是的,我以前不知道。)

现在,我的两个问题得到了很好的解决。我写这个希望是希望它可以帮助具有类似心态的其他人。

At first I was as reluctant as @fmark to switch from optparse to argparse, because:

  1. I thought the difference was not that huge.
  2. Quite some VPS still provides Python 2.6 by default.

Then I saw this doc, argparse outperforms optparse, especially when talking about generating meaningful help message: http://argparse.googlecode.com/svn/trunk/doc/argparse-vs-optparse.html

And then I saw “argparse vs. optparse” by @Nicholas, saying we can have argparse available in python <2.7 (Yep, I didn’t know that before.)

Now my two concerns are well addressed. I wrote this hoping it will help others with a similar mindset.


不带参数的Python argparse命令行标志

问题:不带参数的Python argparse命令行标志

如何在命令行参数中添加可选标志?

例如。所以我可以写

python myprog.py 

要么

python myprog.py -w

我试过了

parser.add_argument('-w')

但是我收到一条错误消息说

Usage [-w W]
error: argument -w: expected one argument

我认为这意味着它需要-w选项的参数值。接受旗帜的方式是什么?

我在这个问题上发现http://docs.python.org/library/argparse.html相当不透明。

How do I add an optional flag to my command line args?

eg. so I can write

python myprog.py 

or

python myprog.py -w

I tried

parser.add_argument('-w')

But I just get an error message saying

Usage [-w W]
error: argument -w: expected one argument

which I take it means that it wants an argument value for the -w option. What’s the way of just accepting a flag?

I’m finding http://docs.python.org/library/argparse.html rather opaque on this question.


回答 0

如您所愿,参数w在命令行中的-w之后需要一个值。如果您只是想通过设置变量True或来翻转开关False,请访问http://docs.python.org/dev/library/argparse.html#action(特别是store_true和store_false)

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-w', action='store_true')

其中action='store_true'暗示default=False

相反,您可能有action='store_false',这意味着default=True

As you have it, the argument w is expecting a value after -w on the command line. If you are just looking to flip a switch by setting a variable True or False, have a look at http://docs.python.org/dev/library/argparse.html#action (specifically store_true and store_false)

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-w', action='store_true')

where action='store_true' implies default=False.

Conversely, you could haveaction='store_false', which implies default=True.


回答 1

添加一个快速片段以使其可以执行:

资料来源:myparser.py

import argparse
parser = argparse.ArgumentParser(description="Flip a switch by setting a flag")
parser.add_argument('-w', action='store_true')

args = parser.parse_args()
print args.w

用法:

python myparser.py -w
>> True

Adding a quick snippet to have it ready to execute:

Source: myparser.py

import argparse
parser = argparse.ArgumentParser(description="Flip a switch by setting a flag")
parser.add_argument('-w', action='store_true')

args = parser.parse_args()
print args.w

Usage:

python myparser.py -w
>> True

回答 2

这是一种快速的方法,sys尽管功能有限,但除了.. 之外不需要任何其他功能:

flag = "--flag" in sys.argv[1:]

[1:] 如果完整的文件名是 --flag

Here’s a quick way to do it, won’t require anything besides sys.. though functionality is limited:

flag = "--flag" in sys.argv[1:]

[1:] is in case if the full file name is --flag


Python argparse:如何在帮助文本中插入换行符?

问题:Python argparse:如何在帮助文本中插入换行符?

argparse在Python 2.7中用于解析输入选项。我的选择之一是多项选择。我想在其帮助文本中列出一个列表,例如

from argparse import ArgumentParser

parser = ArgumentParser(description='test')

parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
    help="Some option, where\n"
         " a = alpha\n"
         " b = beta\n"
         " g = gamma\n"
         " d = delta\n"
         " e = epsilon")

parser.parse_args()

但是,argparse删除所有换行符和连续的空格。结果看起来像

〜/下载:52 $ python2.7 x.py -h
用法:x.py [-h] [-g {a,b,g,d,e}]

测试

可选参数:
  -h,--help显示此帮助消息并退出
  -g {a,b,g,d,e}某些选项,其中a = alpha b = beta g = gamma d = delta e
                  = epsilon

如何在帮助文本中插入换行符?

I’m using argparse in Python 2.7 for parsing input options. One of my options is a multiple choice. I want to make a list in its help text, e.g.

from argparse import ArgumentParser

parser = ArgumentParser(description='test')

parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
    help="Some option, where\n"
         " a = alpha\n"
         " b = beta\n"
         " g = gamma\n"
         " d = delta\n"
         " e = epsilon")

parser.parse_args()

However, argparse strips all newlines and consecutive spaces. The result looks like

~/Downloads:52$ python2.7 x.py -h
usage: x.py [-h] [-g {a,b,g,d,e}]

test

optional arguments:
  -h, --help      show this help message and exit
  -g {a,b,g,d,e}  Some option, where a = alpha b = beta g = gamma d = delta e
                  = epsilon

How to insert newlines in the help text?


回答 0

尝试使用RawTextHelpFormatter

from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)

Try using RawTextHelpFormatter:

from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)

回答 1

如果您只想覆盖一个选项,则不应使用RawTextHelpFormatter。而是子类化,HelpFormatter并为应该“原始”处理的选项提供特殊的介绍(我使用"R|rest of help"):

import argparse

class SmartFormatter(argparse.HelpFormatter):

    def _split_lines(self, text, width):
        if text.startswith('R|'):
            return text[2:].splitlines()  
        # this is the RawTextHelpFormatter._split_lines
        return argparse.HelpFormatter._split_lines(self, text, width)

并使用它:

from argparse import ArgumentParser

parser = ArgumentParser(description='test', formatter_class=SmartFormatter)

parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
    help="R|Some option, where\n"
         " a = alpha\n"
         " b = beta\n"
         " g = gamma\n"
         " d = delta\n"
         " e = epsilon")

parser.parse_args()

对于其他任何.add_argument()不以帮助开头的呼叫,R|都将照常进行包装。

这是我对argparse进行改进的一部分。完整的SmartFormatter还支持将默认值添加到所有选项,以及实用程序描述的原始输入。完整版本具有自己的_split_lines方法,因此可以保留对版本字符串所做的任何格式化:

parser.add_argument('--version', '-v', action="version",
                    version="version...\n   42!")

If you just want to override the one option, you should not use RawTextHelpFormatter. Instead subclass the HelpFormatter and provide a special intro for the options that should be handled “raw” (I use "R|rest of help"):

import argparse

class SmartFormatter(argparse.HelpFormatter):

    def _split_lines(self, text, width):
        if text.startswith('R|'):
            return text[2:].splitlines()  
        # this is the RawTextHelpFormatter._split_lines
        return argparse.HelpFormatter._split_lines(self, text, width)

And use it:

from argparse import ArgumentParser

parser = ArgumentParser(description='test', formatter_class=SmartFormatter)

parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
    help="R|Some option, where\n"
         " a = alpha\n"
         " b = beta\n"
         " g = gamma\n"
         " d = delta\n"
         " e = epsilon")

parser.parse_args()

Any other calls to .add_argument() where the help does not start with R| will be wrapped as normal.

This is part of my improvements on argparse. The full SmartFormatter also supports adding the defaults to all options, and raw input of the utilities description. The full version has its own _split_lines method, so that any formatting done to e.g. version strings is preserved:

parser.add_argument('--version', '-v', action="version",
                    version="version...\n   42!")

回答 2

另一个简单的方法是包括textwrap

例如,

import argparse, textwrap
parser = argparse.ArgumentParser(description='some information',
        usage='use "python %(prog)s --help" for more information',
        formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('--argument', default=somedefault, type=sometype,
        help= textwrap.dedent('''\
        First line
        Second line
        More lines ... '''))

这样,我们可以避免每条输出线前面有很长的空白空间。

usage: use "python your_python_program.py --help" for more information

Prepare input file

optional arguments:
-h, --help            show this help message and exit
--argument ARGUMENT
                      First line
                      Second line
                      More lines ...

Another easy way to do it is to include textwrap.

For example,

import argparse, textwrap
parser = argparse.ArgumentParser(description='some information',
        usage='use "python %(prog)s --help" for more information',
        formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('--argument', default=somedefault, type=sometype,
        help= textwrap.dedent('''\
        First line
        Second line
        More lines ... '''))

In this way, we can avoid the long empty space in front of each output line.

usage: use "python your_python_program.py --help" for more information

Prepare input file

optional arguments:
-h, --help            show this help message and exit
--argument ARGUMENT
                      First line
                      Second line
                      More lines ...

回答 3

我也遇到过类似的问题(Python 2.7.6)。我尝试使用以下方式将描述部分分解为几行RawTextHelpFormatter

parser = ArgumentParser(description="""First paragraph 

                                       Second paragraph

                                       Third paragraph""",  
                                       usage='%(prog)s [OPTIONS]', 
                                       formatter_class=RawTextHelpFormatter)

options = parser.parse_args()

并得到:

用法:play-with-argparse.py [选项]

第一段 

                        第二段

                        第三段

可选参数:
  -h,--help显示此帮助消息并退出

所以RawTextHelpFormatter不是解决方案。因为它按源代码中的显示方式打印描述,所以保留了所有空白字符(我想在源代码中保留额外的制表符,以提高可读性,但我不想将它们全部打印出来。同样,原始格式化程序不会在换行时换行太长,例如超过80个字符)。

感谢@Anton启发了上面的正确方向。但是该解决方案需要稍作修改才能格式化描述部分。

无论如何,需要自定义格式化程序。我扩展了现有的HelpFormatter类并覆盖了这样的_fill_text方法:

import textwrap as _textwrap
class MultilineFormatter(argparse.HelpFormatter):
    def _fill_text(self, text, width, indent):
        text = self._whitespace_matcher.sub(' ', text).strip()
        paragraphs = text.split('|n ')
        multiline_text = ''
        for paragraph in paragraphs:
            formatted_paragraph = _textwrap.fill(paragraph, width, initial_indent=indent, subsequent_indent=indent) + '\n\n'
            multiline_text = multiline_text + formatted_paragraph
        return multiline_text

与来自argparse模块的原始源代码进行比较:

def _fill_text(self, text, width, indent):
    text = self._whitespace_matcher.sub(' ', text).strip()
    return _textwrap.fill(text, width, initial_indent=indent,
                                       subsequent_indent=indent)

在原始代码中,整个描述被包装。在上面的自定义格式化程序中,整个文本分为几个块,并且每个块都独立进行格式化。

因此,借助自定义格式化程序:

parser = ArgumentParser(description= """First paragraph 
                                        |n                              
                                        Second paragraph
                                        |n
                                        Third paragraph""",  
                usage='%(prog)s [OPTIONS]',
                formatter_class=MultilineFormatter)

options = parser.parse_args()

输出为:

用法:play-with-argparse.py [选项]

第一段

第二段

第三段

可选参数:
  -h,--help显示此帮助消息并退出

I’ve faced similar issue (Python 2.7.6). I’ve tried to break down description section into several lines using RawTextHelpFormatter:

parser = ArgumentParser(description="""First paragraph 

                                       Second paragraph

                                       Third paragraph""",  
                                       usage='%(prog)s [OPTIONS]', 
                                       formatter_class=RawTextHelpFormatter)

options = parser.parse_args()

And got:

usage: play-with-argparse.py [OPTIONS]

First paragraph 

                        Second paragraph

                        Third paragraph

optional arguments:
  -h, --help  show this help message and exit

So RawTextHelpFormatter is not a solution. Because it prints description as it appears in source code, preserving all whitespace characters (I want to keep extra tabs in my source code for readability but I don’t want to print them all. Also raw formatter doesn’t wrap line when it is too long, more than 80 characters for example).

Thanks to @Anton who inspired the right direction above. But that solution needs slight modification in order to format description section.

Anyway, custom formatter is needed. I extended existing HelpFormatter class and overrode _fill_text method like this:

import textwrap as _textwrap
class MultilineFormatter(argparse.HelpFormatter):
    def _fill_text(self, text, width, indent):
        text = self._whitespace_matcher.sub(' ', text).strip()
        paragraphs = text.split('|n ')
        multiline_text = ''
        for paragraph in paragraphs:
            formatted_paragraph = _textwrap.fill(paragraph, width, initial_indent=indent, subsequent_indent=indent) + '\n\n'
            multiline_text = multiline_text + formatted_paragraph
        return multiline_text

Compare with the original source code coming from argparse module:

def _fill_text(self, text, width, indent):
    text = self._whitespace_matcher.sub(' ', text).strip()
    return _textwrap.fill(text, width, initial_indent=indent,
                                       subsequent_indent=indent)

In the original code the whole description is being wrapped. In custom formatter above the whole text is split into several chunks, and each of them is formatted independently.

So with aid of custom formatter:

parser = ArgumentParser(description= """First paragraph 
                                        |n                              
                                        Second paragraph
                                        |n
                                        Third paragraph""",  
                usage='%(prog)s [OPTIONS]',
                formatter_class=MultilineFormatter)

options = parser.parse_args()

the output is:

usage: play-with-argparse.py [OPTIONS]

First paragraph

Second paragraph

Third paragraph

optional arguments:
  -h, --help  show this help message and exit

回答 4

我想在说明文字中同时包含手动换行符和自动换行符;但是这里没有任何建议对我有用-因此我最终修改了此处答案中给出的SmartFormatter类;尽管argparse方法名称不是公共API的问题,但这是我所拥有的(称为的文件test.py):

import argparse
from argparse import RawDescriptionHelpFormatter

# call with: python test.py -h

class SmartDescriptionFormatter(argparse.RawDescriptionHelpFormatter):
  #def _split_lines(self, text, width): # RawTextHelpFormatter, although function name might change depending on Python
  def _fill_text(self, text, width, indent): # RawDescriptionHelpFormatter, although function name might change depending on Python
    #print("splot",text)
    if text.startswith('R|'):
      paragraphs = text[2:].splitlines()
      rebroken = [argparse._textwrap.wrap(tpar, width) for tpar in paragraphs]
      #print(rebroken)
      rebrokenstr = []
      for tlinearr in rebroken:
        if (len(tlinearr) == 0):
          rebrokenstr.append("")
        else:
          for tlinepiece in tlinearr:
            rebrokenstr.append(tlinepiece)
      #print(rebrokenstr)
      return '\n'.join(rebrokenstr) #(argparse._textwrap.wrap(text[2:], width))
    # this is the RawTextHelpFormatter._split_lines
    #return argparse.HelpFormatter._split_lines(self, text, width)
    return argparse.RawDescriptionHelpFormatter._fill_text(self, text, width, indent)

parser = argparse.ArgumentParser(formatter_class=SmartDescriptionFormatter, description="""R|Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah .blah blah

Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl blah bl bl a blah, bla blahb bl:

  blah blahblah blah bl blah blahblah""")

options = parser.parse_args()

这是在2.7和3.4中的工作方式:

$ python test.py -h
usage: test.py [-h]

Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah
.blah blah

Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl
blah bl bl a blah, bla blahb bl:

  blah blahblah blah bl blah blahblah

optional arguments:
  -h, --help  show this help message and exit

I wanted to have both manual line breaks in the description text, and auto wrapping of it; but none of the suggestions here worked for me – so I ended up modifying the SmartFormatter class given in the answers here; the issues with the argparse method names not being a public API notwithstanding, here is what I have (as a file called test.py):

import argparse
from argparse import RawDescriptionHelpFormatter

# call with: python test.py -h

class SmartDescriptionFormatter(argparse.RawDescriptionHelpFormatter):
  #def _split_lines(self, text, width): # RawTextHelpFormatter, although function name might change depending on Python
  def _fill_text(self, text, width, indent): # RawDescriptionHelpFormatter, although function name might change depending on Python
    #print("splot",text)
    if text.startswith('R|'):
      paragraphs = text[2:].splitlines()
      rebroken = [argparse._textwrap.wrap(tpar, width) for tpar in paragraphs]
      #print(rebroken)
      rebrokenstr = []
      for tlinearr in rebroken:
        if (len(tlinearr) == 0):
          rebrokenstr.append("")
        else:
          for tlinepiece in tlinearr:
            rebrokenstr.append(tlinepiece)
      #print(rebrokenstr)
      return '\n'.join(rebrokenstr) #(argparse._textwrap.wrap(text[2:], width))
    # this is the RawTextHelpFormatter._split_lines
    #return argparse.HelpFormatter._split_lines(self, text, width)
    return argparse.RawDescriptionHelpFormatter._fill_text(self, text, width, indent)

parser = argparse.ArgumentParser(formatter_class=SmartDescriptionFormatter, description="""R|Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah .blah blah

Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl blah bl bl a blah, bla blahb bl:

  blah blahblah blah bl blah blahblah""")

options = parser.parse_args()

This is how it works in 2.7 and 3.4:

$ python test.py -h
usage: test.py [-h]

Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah
.blah blah

Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl
blah bl bl a blah, bla blahb bl:

  blah blahblah blah bl blah blahblah

optional arguments:
  -h, --help  show this help message and exit

回答 5

从上述的SmartFomatter开始,我结束了该解决方案:

class SmartFormatter(argparse.HelpFormatter):
    '''
         Custom Help Formatter used to split help text when '\n' was 
         inserted in it.
    '''

    def _split_lines(self, text, width):
        r = []
        for t in text.splitlines(): r.extend(argparse.HelpFormatter._split_lines(self, t, width))
        return r

请注意,奇怪的是,传递给顶级解析器的formatter_class参数没有被sub_parsers继承,必须为每个创建的sub_parser再次传递它。

Starting from SmartFomatter described above, I ended to that solution:

class SmartFormatter(argparse.HelpFormatter):
    '''
         Custom Help Formatter used to split help text when '\n' was 
         inserted in it.
    '''

    def _split_lines(self, text, width):
        r = []
        for t in text.splitlines(): r.extend(argparse.HelpFormatter._split_lines(self, t, width))
        return r

Note that strangely the formatter_class argument passed to top level parser is not inheritated by sub_parsers, one must pass it again for each created sub_parser.


回答 6

前言

对于这个问题,argparse.RawTextHelpFormatter对我有帮助。

现在,我想分享如何使用argparse

我知道这可能与问题无关,

但是这些问题困扰了我一段时间。

因此,我想分享自己的经验,希望对您有所帮助。

开始了。

第三方模块

colorama:用于更改文本颜色:pip install colorama

使ANSI转义字符序列(用于生成彩色的终端文本和光标定位)在MS Windows下工作

import colorama
from colorama import Fore, Back
from pathlib import Path
from os import startfile, system

SCRIPT_DIR = Path(__file__).resolve().parent
TEMPLATE_DIR = SCRIPT_DIR.joinpath('.')


def main(args):
    ...


if __name__ == '__main__':
    colorama.init(autoreset=True)

    from argparse import ArgumentParser, RawTextHelpFormatter

    format_text = FormatText([(20, '<'), (60, '<')])
    yellow_dc = format_text.new_dc(fore_color=Fore.YELLOW)
    green_dc = format_text.new_dc(fore_color=Fore.GREEN)
    red_dc = format_text.new_dc(fore_color=Fore.RED, back_color=Back.LIGHTYELLOW_EX)

    script_description = \
        '\n'.join([desc for desc in
                   [f'\n{green_dc(f"python {Path(__file__).name} [REFERENCE TEMPLATE] [OUTPUT FILE NAME]")} to create template.',
                    f'{green_dc(f"python {Path(__file__).name} -l *")} to get all available template',
                    f'{green_dc(f"python {Path(__file__).name} -o open")} open template directory so that you can put your template file there.',
                    # <- add your own description
                    ]])
    arg_parser = ArgumentParser(description=yellow_dc('CREATE TEMPLATE TOOL'),
                                # conflict_handler='resolve',
                                usage=script_description, formatter_class=RawTextHelpFormatter)

    arg_parser.add_argument("ref", help="reference template", nargs='?')
    arg_parser.add_argument("outfile", help="output file name", nargs='?')
    arg_parser.add_argument("action_number", help="action number", nargs='?', type=int)
    arg_parser.add_argument('--list', "-l", dest='list',
                            help=f"example: {green_dc('-l *')} \n"
                                 "description: list current available template. (accept regex)")

    arg_parser.add_argument('--option', "-o", dest='option',
                            help='\n'.join([format_text(msg_data_list) for msg_data_list in [
                                ['example', 'description'],
                                [green_dc('-o open'), 'open template directory so that you can put your template file there.'],
                                [green_dc('-o run'), '...'],
                                [green_dc('-o ...'), '...'],
                                # <- add your own description
                            ]]))

    g_args = arg_parser.parse_args()
    task_run_list = [[False, lambda: startfile('.')] if g_args.option == 'open' else None,
                     [False, lambda: [print(template_file_path.stem) for template_file_path in TEMPLATE_DIR.glob(f'{g_args.list}.py')]] if g_args.list else None,
                     # <- add your own function
                     ]
    for leave_flag, func in [task_list for task_list in task_run_list if task_list]:
        func()
        if leave_flag:
            exit(0)

    # CHECK POSITIONAL ARGUMENTS
    for attr_name, value in vars(g_args).items():
        if attr_name.startswith('-') or value is not None:
            continue
        system('cls')
        print(f'error required values of {red_dc(attr_name)} is None')
        print(f"if you need help, please use help command to help you: {red_dc(f'python {__file__} -h')}")
        exit(-1)
    main(g_args)

其中的类别FormatText如下

class FormatText:
    __slots__ = ['align_list']

    def __init__(self, align_list: list, autoreset=True):
        """
        USAGE::

            format_text = FormatText([(20, '<'), (60, '<')])
            red_dc = format_text.new_dc(fore_color=Fore.RED)
            print(red_dc(['column 1', 'column 2']))
            print(red_dc('good morning'))
        :param align_list:
        :param autoreset:
        """
        self.align_list = align_list
        colorama.init(autoreset=autoreset)

    def __call__(self, text_list: list):
        if len(text_list) != len(self.align_list):
            if isinstance(text_list, str):
                return text_list
            raise AttributeError
        return ' '.join(f'{txt:{flag}{int_align}}' for txt, (int_align, flag) in zip(text_list, self.align_list))

    def new_dc(self, fore_color: Fore = Fore.GREEN, back_color: Back = ""):  # DECORATOR
        """create a device context"""
        def wrap(msgs):
            return back_color + fore_color + self(msgs) + Fore.RESET
        return wrap

Preface

For this question, argparse.RawTextHelpFormatter is helpful to me.

Now, I want to share how do I use the argparse.

I know it may not be related to question,

but these questions have been bothered me for a while.

So I want to share my experience, hope that will be helpful for someone.

Here we go.

3rd Party Modules

colorama: for change the text color: pip install colorama

Makes ANSI escape character sequences (for producing colored terminal text and cursor positioning) work under MS Windows

Example

import colorama
from colorama import Fore, Back
from pathlib import Path
from os import startfile, system

SCRIPT_DIR = Path(__file__).resolve().parent
TEMPLATE_DIR = SCRIPT_DIR.joinpath('.')


def main(args):
    ...


if __name__ == '__main__':
    colorama.init(autoreset=True)

    from argparse import ArgumentParser, RawTextHelpFormatter

    format_text = FormatText([(20, '<'), (60, '<')])
    yellow_dc = format_text.new_dc(fore_color=Fore.YELLOW)
    green_dc = format_text.new_dc(fore_color=Fore.GREEN)
    red_dc = format_text.new_dc(fore_color=Fore.RED, back_color=Back.LIGHTYELLOW_EX)

    script_description = \
        '\n'.join([desc for desc in
                   [f'\n{green_dc(f"python {Path(__file__).name} [REFERENCE TEMPLATE] [OUTPUT FILE NAME]")} to create template.',
                    f'{green_dc(f"python {Path(__file__).name} -l *")} to get all available template',
                    f'{green_dc(f"python {Path(__file__).name} -o open")} open template directory so that you can put your template file there.',
                    # <- add your own description
                    ]])
    arg_parser = ArgumentParser(description=yellow_dc('CREATE TEMPLATE TOOL'),
                                # conflict_handler='resolve',
                                usage=script_description, formatter_class=RawTextHelpFormatter)

    arg_parser.add_argument("ref", help="reference template", nargs='?')
    arg_parser.add_argument("outfile", help="output file name", nargs='?')
    arg_parser.add_argument("action_number", help="action number", nargs='?', type=int)
    arg_parser.add_argument('--list', "-l", dest='list',
                            help=f"example: {green_dc('-l *')} \n"
                                 "description: list current available template. (accept regex)")

    arg_parser.add_argument('--option', "-o", dest='option',
                            help='\n'.join([format_text(msg_data_list) for msg_data_list in [
                                ['example', 'description'],
                                [green_dc('-o open'), 'open template directory so that you can put your template file there.'],
                                [green_dc('-o run'), '...'],
                                [green_dc('-o ...'), '...'],
                                # <- add your own description
                            ]]))

    g_args = arg_parser.parse_args()
    task_run_list = [[False, lambda: startfile('.')] if g_args.option == 'open' else None,
                     [False, lambda: [print(template_file_path.stem) for template_file_path in TEMPLATE_DIR.glob(f'{g_args.list}.py')]] if g_args.list else None,
                     # <- add your own function
                     ]
    for leave_flag, func in [task_list for task_list in task_run_list if task_list]:
        func()
        if leave_flag:
            exit(0)

    # CHECK POSITIONAL ARGUMENTS
    for attr_name, value in vars(g_args).items():
        if attr_name.startswith('-') or value is not None:
            continue
        system('cls')
        print(f'error required values of {red_dc(attr_name)} is None')
        print(f"if you need help, please use help command to help you: {red_dc(f'python {__file__} -h')}")
        exit(-1)
    main(g_args)


Where the class of FormatText is the following

class FormatText:
    __slots__ = ['align_list']

    def __init__(self, align_list: list, autoreset=True):
        """
        USAGE::

            format_text = FormatText([(20, '<'), (60, '<')])
            red_dc = format_text.new_dc(fore_color=Fore.RED)
            print(red_dc(['column 1', 'column 2']))
            print(red_dc('good morning'))
        :param align_list:
        :param autoreset:
        """
        self.align_list = align_list
        colorama.init(autoreset=autoreset)

    def __call__(self, text_list: list):
        if len(text_list) != len(self.align_list):
            if isinstance(text_list, str):
                return text_list
            raise AttributeError
        return ' '.join(f'{txt:{flag}{int_align}}' for txt, (int_align, flag) in zip(text_list, self.align_list))

    def new_dc(self, fore_color: Fore = Fore.GREEN, back_color: Back = ""):  # DECORATOR
        """create a device context"""
        def wrap(msgs):
            return back_color + fore_color + self(msgs) + Fore.RESET
        return wrap


用argparse解析布尔值

问题:用argparse解析布尔值

我想使用argparse解析布尔命令行参数,写为“ –foo True”或“ –foo False”。例如:

my_program --my_boolean_flag False

但是,以下测试代码无法满足我的要求:

import argparse
parser = argparse.ArgumentParser(description="My parser")
parser.add_argument("--my_bool", type=bool)
cmd_line = ["--my_bool", "False"]
parsed_args = parser.parse(cmd_line)

可悲的是,parsed_args.my_bool计算结果为True。即使我更改cmd_line["--my_bool", ""],情况也是如此,这令人惊讶,因为bool("")评估为False

如何获取argparse进行解析"False""F"以及它们的小写形式是False什么?

I would like to use argparse to parse boolean command-line arguments written as “–foo True” or “–foo False”. For example:

my_program --my_boolean_flag False

However, the following test code does not do what I would like:

import argparse
parser = argparse.ArgumentParser(description="My parser")
parser.add_argument("--my_bool", type=bool)
cmd_line = ["--my_bool", "False"]
parsed_args = parser.parse(cmd_line)

Sadly, parsed_args.my_bool evaluates to True. This is the case even when I change cmd_line to be ["--my_bool", ""], which is surprising, since bool("") evalutates to False.

How can I get argparse to parse "False", "F", and their lower-case variants to be False?


回答 0

另一个解决方案使用了先前的建议,但存在来自argparse以下情况的“正确”解析错误:

def str2bool(v):
    if isinstance(v, bool):
       return v
    if v.lower() in ('yes', 'true', 't', 'y', '1'):
        return True
    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
        return False
    else:
        raise argparse.ArgumentTypeError('Boolean value expected.')

这对于使用默认值进行切换非常有用。例如

parser.add_argument("--nice", type=str2bool, nargs='?',
                        const=True, default=False,
                        help="Activate nice mode.")

允许我使用:

script --nice
script --nice <bool>

并仍使用默认值(特定于用户设置)。这种方法的一个(间接相关的)缺点是“水罐”可能会引起位置争执-请参阅此相关问题此argparse错误报告

Yet another solution using the previous suggestions, but with the “correct” parse error from argparse:

def str2bool(v):
    if isinstance(v, bool):
       return v
    if v.lower() in ('yes', 'true', 't', 'y', '1'):
        return True
    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
        return False
    else:
        raise argparse.ArgumentTypeError('Boolean value expected.')

This is very useful to make switches with default values; for instance

parser.add_argument("--nice", type=str2bool, nargs='?',
                        const=True, default=False,
                        help="Activate nice mode.")

allows me to use:

script --nice
script --nice <bool>

and still use a default value (specific to the user settings). One (indirectly related) downside with that approach is that the ‘nargs’ might catch a positional argument — see this related question and this argparse bug report.


回答 1

我认为更规范的方法是通过:

command --feature

command --no-feature

argparse 很好地支持此版本:

parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

当然,如果您确实需要--arg <True|False>版本,则可以将其ast.literal_eval作为“类型”或用户定义的函数来传递…

def t_or_f(arg):
    ua = str(arg).upper()
    if 'TRUE'.startswith(ua):
       return True
    elif 'FALSE'.startswith(ua):
       return False
    else:
       pass  #error condition maybe?

I think a more canonical way to do this is via:

command --feature

and

command --no-feature

argparse supports this version nicely:

parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

Of course, if you really want the --arg <True|False> version, you could pass ast.literal_eval as the “type”, or a user defined function …

def t_or_f(arg):
    ua = str(arg).upper()
    if 'TRUE'.startswith(ua):
       return True
    elif 'FALSE'.startswith(ua):
       return False
    else:
       pass  #error condition maybe?

回答 2

我建议mgilson的答案,但有互相排斥的群体
,这样就可以不使用--feature,并--no-feature在同一时间。

command --feature

command --no-feature

但不是

command --feature --no-feature

脚本:

feature_parser = parser.add_mutually_exclusive_group(required=False)
feature_parser.add_argument('--feature', dest='feature', action='store_true')
feature_parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

如果要设置许多帮助器,则可以使用此帮助器:

def add_bool_arg(parser, name, default=False):
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument('--' + name, dest=name, action='store_true')
    group.add_argument('--no-' + name, dest=name, action='store_false')
    parser.set_defaults(**{name:default})

add_bool_arg(parser, 'useful-feature')
add_bool_arg(parser, 'even-more-useful-feature')

I recommend mgilson’s answer but with a mutually exclusive group
so that you cannot use --feature and --no-feature at the same time.

command --feature

and

command --no-feature

but not

command --feature --no-feature

Script:

feature_parser = parser.add_mutually_exclusive_group(required=False)
feature_parser.add_argument('--feature', dest='feature', action='store_true')
feature_parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

You can then use this helper if you are going to set many of them:

def add_bool_arg(parser, name, default=False):
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument('--' + name, dest=name, action='store_true')
    group.add_argument('--no-' + name, dest=name, action='store_false')
    parser.set_defaults(**{name:default})

add_bool_arg(parser, 'useful-feature')
add_bool_arg(parser, 'even-more-useful-feature')

回答 3

这是另一种变体,无需额​​外的行来设置默认值。布尔值始终分配有一个值,以便可以在逻辑语句中使用它而无需预先检查。

import argparse
parser = argparse.ArgumentParser(description="Parse bool")
parser.add_argument("--do-something", default=False, action="store_true" , help="Flag to do something")
args = parser.parse_args()

if args.do_something:
     print("Do something")
else:
     print("Don't do something")
print("Check that args.do_something=" + str(args.do_something) + " is always a bool")

Here is another variation without extra row/s to set default values. The bool always have a value assigned so that it can be used in logical statements without pre-checks.

import argparse
parser = argparse.ArgumentParser(description="Parse bool")
parser.add_argument("--do-something", default=False, action="store_true" , help="Flag to do something")
args = parser.parse_args()

if args.do_something:
     print("Do something")
else:
     print("Don't do something")
print("Check that args.do_something=" + str(args.do_something) + " is always a bool")

回答 4

单线:

parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))

oneliner:

parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))

回答 5

关于什么type=bool以及type='bool'可能意味着什么似乎有些困惑。一个(或两个)是否应该表示“运行函数bool()或”返回布尔值”?就目前而言,它type='bool'毫无意义。 add_argument给出'bool' is not callable错误,与您使用type='foobar'或相同type='int'

但是argparse确实有注册表可以让您定义这样的关键字。它主要用于action,例如`action =’store_true’。您可以通过以下方式查看已注册的关键字:

parser._registries

显示字典

{'action': {None: argparse._StoreAction,
  'append': argparse._AppendAction,
  'append_const': argparse._AppendConstAction,
...
 'type': {None: <function argparse.identity>}}

定义了许多动作,但只有一种类型,默认类型为argparse.identity

这段代码定义了一个’bool’关键字:

def str2bool(v):
  #susendberg's function
  return v.lower() in ("yes", "true", "t", "1")
p = argparse.ArgumentParser()
p.register('type','bool',str2bool) # add type keyword to registries
p.add_argument('-b',type='bool')  # do not use 'type=bool'
# p.add_argument('-b',type=str2bool) # works just as well
p.parse_args('-b false'.split())
Namespace(b=False)

parser.register()没有记录,但也没有隐藏。在大多数情况下,程序员并不需要了解它,因为typeaction取函数和类值。有很多为这两者定义自定义值的stackoverflow示例。


万一从前面的讨论中看bool()不出来,就不意味着“解析字符串”。从Python文档中:

bool(x):使用标准真值测试过程将值转换为布尔值。

与之对比

int(x):将数字或字符串x转换为整数。

There seems to be some confusion as to what type=bool and type='bool' might mean. Should one (or both) mean ‘run the function bool(), or ‘return a boolean’? As it stands type='bool' means nothing. add_argument gives a 'bool' is not callable error, same as if you used type='foobar', or type='int'.

But argparse does have registry that lets you define keywords like this. It is mostly used for action, e.g. `action=’store_true’. You can see the registered keywords with:

parser._registries

which displays a dictionary

{'action': {None: argparse._StoreAction,
  'append': argparse._AppendAction,
  'append_const': argparse._AppendConstAction,
...
 'type': {None: <function argparse.identity>}}

There are lots of actions defined, but only one type, the default one, argparse.identity.

This code defines a ‘bool’ keyword:

def str2bool(v):
  #susendberg's function
  return v.lower() in ("yes", "true", "t", "1")
p = argparse.ArgumentParser()
p.register('type','bool',str2bool) # add type keyword to registries
p.add_argument('-b',type='bool')  # do not use 'type=bool'
# p.add_argument('-b',type=str2bool) # works just as well
p.parse_args('-b false'.split())
Namespace(b=False)

parser.register() is not documented, but also not hidden. For the most part the programmer does not need to know about it because type and action take function and class values. There are lots of stackoverflow examples of defining custom values for both.


In case it isn’t obvious from the previous discussion, bool() does not mean ‘parse a string’. From the Python documentation:

bool(x): Convert a value to a Boolean, using the standard truth testing procedure.

Contrast this with

int(x): Convert a number or string x to an integer.


回答 6

我一直在寻找相同的问题,恕我直言,漂亮的解决方案是:

def str2bool(v):
  return v.lower() in ("yes", "true", "t", "1")

并按照上面的建议使用它来将字符串解析为布尔值。

I was looking for the same issue, and imho the pretty solution is :

def str2bool(v):
  return v.lower() in ("yes", "true", "t", "1")

and using that to parse the string to boolean as suggested above.


回答 7

一个非常类似的方法是使用:

feature.add_argument('--feature',action='store_true')

如果您在命令中设置了参数–feature

 command --feature

如果未设置type –feature,则参数将为True,参数默认始终为False!

A quite similar way is to use:

feature.add_argument('--feature',action='store_true')

and if you set the argument –feature in your command

 command --feature

the argument will be True, if you do not set type –feature the arguments default is always False!


回答 8

除了@mgilson所说的以外,还应注意还有一种ArgumentParser.add_mutually_exclusive_group(required=False)方法可以使执行该操作变得微不足道,--flag并且--no-flag不能同时使用。

In addition to what @mgilson said, it should be noted that there’s also a ArgumentParser.add_mutually_exclusive_group(required=False) method that would make it trivial to enforce that --flag and --no-flag aren’t used at the same time.


回答 9

这适用于我期望的所有功能:

add_boolean_argument(parser, 'foo', default=True)
parser.parse_args([])                   # Whatever the default was
parser.parse_args(['--foo'])            # True
parser.parse_args(['--nofoo'])          # False
parser.parse_args(['--foo=true'])       # True
parser.parse_args(['--foo=false'])      # False
parser.parse_args(['--foo', '--nofoo']) # Error

编码:

def _str_to_bool(s):
    """Convert string to bool (in argparse context)."""
    if s.lower() not in ['true', 'false']:
        raise ValueError('Need bool; got %r' % s)
    return {'true': True, 'false': False}[s.lower()]

def add_boolean_argument(parser, name, default=False):                                                                                               
    """Add a boolean argument to an ArgumentParser instance."""
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '--' + name, nargs='?', default=default, const=True, type=_str_to_bool)
    group.add_argument('--no' + name, dest=name, action='store_false')

This works for everything I expect it to:

add_boolean_argument(parser, 'foo', default=True)
parser.parse_args([])                   # Whatever the default was
parser.parse_args(['--foo'])            # True
parser.parse_args(['--nofoo'])          # False
parser.parse_args(['--foo=true'])       # True
parser.parse_args(['--foo=false'])      # False
parser.parse_args(['--foo', '--nofoo']) # Error

The code:

def _str_to_bool(s):
    """Convert string to bool (in argparse context)."""
    if s.lower() not in ['true', 'false']:
        raise ValueError('Need bool; got %r' % s)
    return {'true': True, 'false': False}[s.lower()]

def add_boolean_argument(parser, name, default=False):                                                                                               
    """Add a boolean argument to an ArgumentParser instance."""
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '--' + name, nargs='?', default=default, const=True, type=_str_to_bool)
    group.add_argument('--no' + name, dest=name, action='store_false')

回答 10

一种更简单的方法是按以下方式使用。

parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])

A simpler way would be to use as below.

parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])

回答 11

最简单 它不灵活,但我更喜欢简单。

  parser.add_argument('--boolean_flag',
                      help='This is a boolean flag.',
                      type=eval, 
                      choices=[True, False], 
                      default='True')

编辑:如果您不信任输入,请不要使用eval

Simplest. It’s not flexible, but I prefer simplicity.

  parser.add_argument('--boolean_flag',
                      help='This is a boolean flag.',
                      type=eval, 
                      choices=[True, False], 
                      default='True')

EDIT: If you don’t trust the input, don’t use eval.


回答 12

最简单的方法是使用选择

parser = argparse.ArgumentParser()
parser.add_argument('--my-flag',choices=('True','False'))

args = parser.parse_args()
flag = args.my_flag == 'True'
print(flag)

不通过–my-flag评估为False。该要求=真,如果你总是希望用户显式地指定一个选择的选项可以添加。

Simplest way would be to use choices:

parser = argparse.ArgumentParser()
parser.add_argument('--my-flag',choices=('True','False'))

args = parser.parse_args()
flag = args.my_flag == 'True'
print(flag)

Not passing –my-flag evaluates to False. The required=True option could be added if you always want the user to explicitly specify a choice.


回答 13

我认为最典型的方法是:

parser.add_argument('--ensure', nargs='*', default=None)

ENSURE = config.ensure is None

I think the most canonical way will be:

parser.add_argument('--ensure', nargs='*', default=None)

ENSURE = config.ensure is None

回答 14

class FlagAction(argparse.Action):
    # From http://bugs.python.org/issue8538

    def __init__(self, option_strings, dest, default=None,
                 required=False, help=None, metavar=None,
                 positive_prefixes=['--'], negative_prefixes=['--no-']):
        self.positive_strings = set()
        self.negative_strings = set()
        for string in option_strings:
            assert re.match(r'--[A-z]+', string)
            suffix = string[2:]
            for positive_prefix in positive_prefixes:
                self.positive_strings.add(positive_prefix + suffix)
            for negative_prefix in negative_prefixes:
                self.negative_strings.add(negative_prefix + suffix)
        strings = list(self.positive_strings | self.negative_strings)
        super(FlagAction, self).__init__(option_strings=strings, dest=dest,
                                         nargs=0, const=None, default=default, type=bool, choices=None,
                                         required=required, help=help, metavar=metavar)

    def __call__(self, parser, namespace, values, option_string=None):
        if option_string in self.positive_strings:
            setattr(namespace, self.dest, True)
        else:
            setattr(namespace, self.dest, False)
class FlagAction(argparse.Action):
    # From http://bugs.python.org/issue8538

    def __init__(self, option_strings, dest, default=None,
                 required=False, help=None, metavar=None,
                 positive_prefixes=['--'], negative_prefixes=['--no-']):
        self.positive_strings = set()
        self.negative_strings = set()
        for string in option_strings:
            assert re.match(r'--[A-z]+', string)
            suffix = string[2:]
            for positive_prefix in positive_prefixes:
                self.positive_strings.add(positive_prefix + suffix)
            for negative_prefix in negative_prefixes:
                self.negative_strings.add(negative_prefix + suffix)
        strings = list(self.positive_strings | self.negative_strings)
        super(FlagAction, self).__init__(option_strings=strings, dest=dest,
                                         nargs=0, const=None, default=default, type=bool, choices=None,
                                         required=required, help=help, metavar=metavar)

    def __call__(self, parser, namespace, values, option_string=None):
        if option_string in self.positive_strings:
            setattr(namespace, self.dest, True)
        else:
            setattr(namespace, self.dest, False)

回答 15

最简单,最正确的方法是

from distutils import util
arser.add_argument('--feature', dest='feature', type=lambda x:bool(distutils.util.strtobool(x)))

请注意,True值为y,y,t,true,on和1;false值是n,no,f,false,off和0。如果val是其他值,则引发ValueError。

Simplest & most correct way is

from distutils import util
arser.add_argument('--feature', dest='feature', type=lambda x:bool(distutils.util.strtobool(x)))

Do note that True values are y, yes, t, true, on and 1; false values are n, no, f, false, off and 0. Raises ValueError if val is anything else.


回答 16

快速简便,但仅适用于参数0或1:

parser.add_argument("mybool", default=True,type=lambda x: bool(int(x)))
myargs=parser.parse_args()
print(myargs.mybool)

从终端调用后,输出将为“ False”:

python myscript.py 0

Quick and easy, but only for arguments 0 or 1:

parser.add_argument("mybool", default=True,type=lambda x: bool(int(x)))
myargs=parser.parse_args()
print(myargs.mybool)

The output will be “False” after calling from terminal:

python myscript.py 0

回答 17

类似于@Akash,但这是我使用的另一种方法。它之所以有用strlambda是因为python lambda总是给我一种外星人的感觉。

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument("--my_bool", type=str, default="False")
args = parser.parse_args()

if bool(strtobool(args.my_bool)) is True:
    print("OK")

Similar to @Akash but here is another approach that I’ve used. It uses str than lambda because python lambda always gives me an alien-feelings.

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument("--my_bool", type=str, default="False")
args = parser.parse_args()

if bool(strtobool(args.my_bool)) is True:
    print("OK")

回答 18

为了改善@Akash Desarda的答案,您可以做

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument("--foo", 
    type=lambda x:bool(strtobool(x)),
    nargs='?', const=True, default=False)
args = parser.parse_args()
print(args.foo)

它支持 python test.py --foo

(base) [costa@costa-pc code]$ python test.py
False
(base) [costa@costa-pc code]$ python test.py --foo 
True
(base) [costa@costa-pc code]$ python test.py --foo True
True
(base) [costa@costa-pc code]$ python test.py --foo False
False

As an improvement to @Akash Desarda ‘s answer, you could do

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument("--foo", 
    type=lambda x:bool(strtobool(x)),
    nargs='?', const=True, default=False)
args = parser.parse_args()
print(args.foo)

And it supports python test.py --foo

(base) [costa@costa-pc code]$ python test.py
False
(base) [costa@costa-pc code]$ python test.py --foo 
True
(base) [costa@costa-pc code]$ python test.py --foo True
True
(base) [costa@costa-pc code]$ python test.py --foo False
False