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

26 投票
3 回答
12920 浏览
提问于 2025-04-18 17:14

我正在使用 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 模块呢?

3 个回答

8

%(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

相比于 sys.argv[0],一个优点是无论你从哪里调用,它的信息都不会改变:

cd ..
./mydir/main.py

详细信息请查看: https://docs.python.org/3/library/argparse.html#prog

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

在 Python 3.5.2 上测试过。

12

当然,正确的方法是:

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

但假设你有一个很好的理由,导致你不能使用 import sys,但可以使用 import 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。

35

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_sysargparse 模块的私有属性,对应它们没有下划线的版本。需要注意的是,由于使用了 os.basename(),这个值只会是脚本的文件名,而不是它的完整路径,这个完整路径可能在 sys.argv[0] 中,但这取决于操作系统)。

撰写回答