如何使用argparse获取程序名称?

26

我正在使用argparse来解析命令行参数。在查看argparse的文档时,我只能看到使用不同程序名称的选项。

我希望能够使用默认的程序名称,而不必导入sys。据我所知,在argparse中没有任何东西会返回程序名称。

import argparse

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

print(dir(args))

这是输出结果:

['__class__', '__contains__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_get_args', '_get_kwargs']

还有其他方法可以在不导入sys模块的情况下检索程序名称吗?


4
为什么你不想在这种情况下导入sys模块?如果需要的话,你只需要导入argv模块:from sys import argv - Kevin London
我是否错误地认为argparse是一个包装在sys.argv[]上的模块?由于argparse解析所有命令行参数,因此它不应该也包含程序名称以使代码更清晰吗?在我看来,当sys.argv[0]突然出现在代码中时,它看起来相当奇怪,而在其他地方都是argparse。 - VSN
1
argparse 导入 sys 作为 _sys。所以理论上你可以使用:argparse._sys.argv[0]。还要注意的是,argparse_sys.argv[1:] 获取它解析的命令行字符串。 - hpaulj
参见:https://stackoverflow.com/a/17406225/1959808 - 0 _
3个回答

34

ArgumentParser 实例有一个 prog 属性,我认为这就是你想要的。

import argparse

parser = argparse.ArgumentParser()
print('parser.prog: {}'.format(parser.prog))

我通过阅读模块源代码Lib/argparse.py,特别是查看class ArgumentParser定义来发现这一点。由于该属性的名称不以下划线字符开头,因此我认为它是公共的。

更新

我看到,至少现在,ArgumentParser实例的prog属性已经被记录在Python 2文档Python 3文档中(自从问这个问题以来)。所以,是的,它是公共的,在两个版本中,如果在创建ArgumentParser时未作为关键字参数提供,则默认为prog = _os.path.basename(_sys.argv[0])(其中_os_sys是与其非下划线前缀对应的私有argparse模块属性。请注意,由于使用了os.basename(),这仅是脚本的文件名,而不是可能(它依赖于操作系统)在sys.argv[0]中的完整路径。


12

当然,正确的方式应该是:

>>> import sys
>>> print sys.argv[0]
    scripts/script.py

假设有一个很好的理由阻止您导入sys,但允许您导入argparse,那么让我们试着使用martineau发现的prog:

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> print parser.prog
    script.py

正如hpaulj所指出的那样,这只包含文件名而不是像sys.argv[0]那样的完整路径,因为模块argparse.py正在使用prog = os.path.basename(sys.argv[0])

但是argparse必须使用sys,因此它需要在argparse命名空间中可访问。 让我们检查一下:

>>> import argparse
>>> print argparse.__dict__
    { ..., '_sys': <module 'sys' (built-in)>, ... }

在这里!让我们尝试使用_sys

>>> import argparse
>>> print argparse._sys.argv[0]
    scripts/script.py

你正在使用sys!当然,但我没有导入它,只有argparse,这就是问题所在!

当然,这有一些禁忌:

  • 不应该使用其他命名空间中以___为前缀的变量,它们被在内部使用
  • 不应该依赖于其他模块的导入,它们可能会更改。
  • 不应该依赖于未记录的API,它们可能会更改。

总而言之

这很有趣,但最好还是坚持使用import sys,直到argparse发布一个访问sys.argv[0]的API为止。


2
感谢您提供的所有细节!虽然如此,我还是选择接受@martineau的答案,因为它直接回答了我的问题。 - VSN

7

%(prog)argparse 帮助文本中的用法

这通常是在帮助文本内部提供如何使用命令的示例时的常见用法。

main.py

#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser(
        description="Do something cool. My name is: %(prog)s",
    epilog="""
This is how you do it:

    %(prog)s yourarg
""",
    formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('somearg', help='also works here: %(prog)s')
args = parser.parse_args()

然后:

./main.py -h

提供:

usage: main.py [-h] somearg

Do something cool. My name is: main.py

positional arguments:
  somearg     also works here: main.py

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

This is how you do it:

    main.py yourarg
< p>与sys.argv [0]相比的一个优点是,无论您从哪里调用它,消息都不会改变:

cd ..
./mydir/main.py

文档地址:https://docs.python.org/zh-cn/3/library/argparse.html#prog

请注意,无论是从sys.argv[0]还是从prog=参数确定的程序名称都可以在帮助消息中使用%(prog)s格式说明符。

测试环境:Python 3.5.2。


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