Python argparse:可为命名或位置参数的命令行参数

14

我正在尝试制作一个Python程序,使用argparse模块解析命令行选项。

我想创建一个可选的参数,可以是命名参数或位置参数。例如,我希望 myScript --username=batmanmyScript batman 做相同的事情。同时,myScript 也应该是有效的,不需要指定用户名。这是否可能?如果是,如何实现呢?

我尝试了类似下面代码的各种方法,但都没有成功。

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-u", "--user-name", default="admin")
group.add_argument("user-name", default="admin")
args = parser.parse_args()

编辑:上面的代码会抛出异常,显示ValueError: mutually exclusive arguments must be optional

我正在使用Python 2.7.2和OS X 10.8.4。

编辑:我尝试了Gabriel Jacobsohn的建议,但在某些情况下无法正常工作。

我尝试了这个:

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-u", "--user-name", default="admin", nargs="?")
group.add_argument("user_name", default="admin", nargs="?")
args = parser.parse_args()
print(args)

运行myScript batman将打印Namespace(user_name='batman'),但myScript -u batmanmyScript --user-name=batman将打印Namespace(user_name='admin')

我尝试在第一个add_argument行中将名称user-name更改为user_name,有时会导致命名空间中同时出现batmanadmin,或者根据程序运行方式而出现错误。

我尝试在第二个add_argument行中将名称user_name更改为user-name,但这将根据程序运行方式打印Namespace(user-name='batman', user_name='admin')Namespace(user-name='admin', user_name='batman')


我想提一下,我正在尝试做的基本上与 Ack--match 参数所做的是相同的事情。 - Elias Zamaria
1
请查看这个问题 - twil
不知何故我没有注意到那个问题。请随意将此问题标记为那个问题的副本。 - Elias Zamaria
3个回答

9
< p > ArgumentParser 的工作方式是,在解析可选参数后,总是检查任何尾随的位置参数。因此,如果您有一个与可选参数同名且未在命令行中出现的位置参数,则它保证会覆盖可选参数(使用其默认值或者None)。

坦白地说,至少在互斥组中使用时,这似乎是一个错误,因为如果您明确指定了该参数,那么它将是一个错误。

话虽如此,我的建议解决方案是给位置参数一个不同的名称。

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('-u','--username')
group.add_argument('static_username',nargs='?',default='admin')

在解析时,如果有可选的用户名,则使用它,否则回退到位置参数static_username

results = parser.parse_args()
username = results.username or results.static_username

我意识到这不是一个特别简洁的解决方案,但我认为没有任何答案会更好。

5
我认为以下方案可以满足你的所有需求:

这里是一个解决方案:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-u", "--user-name", default="admin")
    # Gather all extra args into a list named "args.extra"
    parser.add_argument("extra", nargs='*')
    args = parser.parse_args()
    # Set args.user_name to first extra arg if it is not given and len(args.extra) > 0
    if args.user_name == parser.get_default("user_name") and args.extra:
        args.user_name = args.extra.pop(0)
    print args

如果你运行myScript -u batman或者myScript --user-name=batman,那么变量args.user_name将会被设置为"batman"。如果你运行myScript batmanargs.user_name也将被设置为"batman"。最后,如果你只运行myScript,那么args.user_name将会被设置为"admin"。
另外,作为额外的奖励,你现在可以在args.extra中找到所有传递给脚本的额外参数。希望这可以帮到你。

我会将 args.username = args.extra[0] 改为 args.username=args.extra.pop(0),这样它就不会出现在两个地方了。 - Perkins
@Perkins:嗯...我喜欢这个。它可以让脚本更加清晰。让我来做吧。 - user2555451
我喜欢你的回答。我做了一个小改动,避免默认用户名出现在两个地方。 - Elias Zamaria
我决定将悬赏奖励授予@James Holderness。我喜欢你的想法,但James的解决方案向用户指出程序调用不允许同时具有命名用户名和位置用户名。 - Elias Zamaria

0
尝试使用 add_argument 方法的 "nargs" 参数。这样对我有效。 现在你可以添加用户名两次, 所以如果需要,必须检查并引发错误。
import argparse
if __name__ == '__main__':
   parser = argparse.ArgumentParser()
   parser.add_argument("-u", "--user-name", default="admin")
   parser.add_argument("user_name", default="admin", nargs="?")
   args = parser.parse_args()
   print(args)

我尝试了你回答中的代码。当我运行myScript batman时,它可以正常工作,但是当我运行myScript -u batman或者myScript --user-name=batman时,它会忽略我的参数并将user_name的值设置为admin - Elias Zamaria

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