argparse中的可选nargs变量

5

我如何使用带有可变nargs的argparse进行条件循环?因此,基本上它应该可以在有或没有参数的情况下运行。 我尝试:

parser = argparse.ArgumentParser(description="output parser")
group = parser.add_mutually_exclusive_group()
group.add_argument("--dos", help="get DOSCAR for plot",
                   nargs="?", metavar=("int"))
args = parser.parse_args()

if args.dos:    
    if len(args.dos) > 1:
        chosen = int(args.dos[0])
        chdos = "at_dos"+args.dos[0]+".dat"
    else:
        chosen = None

    inpt = "DOSY"
    print(chosen)
    print(inpt)

现在,如果我有一个变量,它会打印出一些值,虽然不正确但是会打印出一些值:
$python3 vasp.py --dos 111
111
None   # IT SHOULDN'T BE NONE
DOSY

但没有争论什么。

我也尝试过使用正常的sys.argv,如下:

def get_dos():
    if len(sys.argv) > 2:
        chosen = int(sys.argv[2])
        chdos = "at_dos"+sys.argv[2]+".dat"
    else:
        chosen = None
    inpt = "DOSCAR"
    print(sys.argv)

    print(args.dos)
    print(chosen)
    print(inpt)

在这种情况下,当选项存在时,它会给出正确的结果:
python3 vasp.py --dos 12
['vasp.py', '--dos', '12']
12
12
DOSCAR

但是,再次强调,没有选择就什么也没有:

$python3 vasp.py --dos

我尝试了hpaulj的建议。它给出了:
$python3 tt.py --dos 12
Namespace(dos='12')
1
DOSY

即使没有参数,它仍然不会打印任何东西。


当我运行它并修复无效的语法时,我没有得到None。你使用的Python版本是什么?我已经尝试了3.5.1和2.7.11两个版本,两个版本都可以正常工作。你需要一个[mcve]。 - Morgan Thrapp
1
另外,我认为 len(args.dos) > 1 并不是你想象中的那样。它检查你是否输入了超过1位数字。 - Morgan Thrapp
2
你尝试过使用 print(args) 直接查看解析出来的内容吗? - hpaulj
现在你需要一个能够处理字符串'12'的测试,而不是列表或数字。一个字符串。 - hpaulj
仅使用 --dos 和完全不使用它,它应该做什么? - hpaulj
显示剩余2条评论
3个回答

4
简化您在Ipython会话中的解析器:

要在Ipython中简化解析器:

In [1004]: parser=argparse.ArgumentParser()    
In [1005]: parser.add_argument('--dos', nargs='?')

In [1007]: parser.parse_args('--dos 111'.split())
Out[1007]: Namespace(dos='111')

在这种情况下,args.dos 将是字符串 '111',长度为 3,并且 int(args.dos[0]) 是数字 1。如果你不填写 nargs(默认为 None),也会发生同样的情况。
使用 nargs='?',我还可以在没有参数的情况下使用标志,此时值为默认值 None
In [1013]: parser.parse_args('--dos'.split())
Out[1013]: Namespace(dos=None)

nargs=通常与const一起使用,可以提供便捷的三种操作。如果需要将字符串转换为整数,则可以添加type=int.

In [1015]: parser.add_argument('--dos', nargs='?', type=int,
   default=None, const=123)

In [1016]: parser.parse_args([]) # not used
Out[1016]: Namespace(dos=None)

In [1017]: parser.parse_args('--dos'.split())  # without argument
Out[1017]: Namespace(dos=123)

In [1018]: parser.parse_args('--dos 456'.split())  # with argument
Out[1018]: Namespace(dos=456)

其他像1,'*'和'+'这样的nargs会给你一个列表,可以检查它的长度等信息。

====================

在测试你的argv

if len(sys.argv) > 2:
    chosen = int(sys.argv[2])
    chdos = "at_dos"+sys.argv[2]+".dat"

sys.argv 是一个列表,因此 len 函数会计算是否有足够的元素来应用 sys.argv[2] 步骤。

这不起作用是因为 args.dos 是一个单独的字符串,而不是一个列表。

if len(args.dos) > 1:
    chosen = int(args.dos[0])
    chdos = "at_dos"+args.dos[0]+".dat"

len(args.dos)是字符串中的字符数,args.dos[0]是第一个字符。

============

如果我定义:

def get_dos(argv=None):
    parser=argparse.ArgumentParser()
    parser.add_argument('--dos', type=int, nargs='?')
    args = parser.parse_args(argv)
    chosen = args.dos
    if chosen is not None:
        chdos = 'at_dos%s.dat'%chosen
    else:
        chdos = ''
    return chosen, chdos

这些测试会生成数值,我认为这些数值符合您的需求:
In [1042]: get_dos([])
Out[1042]: (None, '')

In [1043]: get_dos(['--dos'])
Out[1043]: (None, '')

In [1044]: get_dos(['--dos','123'])
Out[1044]: (123, 'at_dos123.dat')

0

你需要将nargs = "?"替换为nargs = "*"。将nargs设置为"?"意味着只有一个可选参数。而你想要的是一个可选参数列表,即"*"。像这样。

import argparse
parser = argparse.ArgumentParser(description="output parser")
group = parser.add_mutually_exclusive_group()
group.add_argument("--dos", help="get DOSCAR for plot",
               nargs="*", metavar=("int"))
args = parser.parse_args()

if args.dos:    
    if len(args.dos) > 1:
        chosen = int(args.dos[0])
        chdos = "at_dos"+args.dos[0]+".dat"
    else:
        chosen = None

    inpt = "DOSY"
    print(chosen)
    print(inpt)

我已经尝试过nargs =“*”。你检查过代码了吗?它还是出现了同样的问题。 - BaRud

0
感谢回复的所有人,尤其是@hpaulj。但他们中的任何一个都没有真正解决我的问题。因此,我采取了另一种方法。我在这里发帖是为了完整性。
#!/usr/bin/python3
import argparse

parser = argparse.ArgumentParser(description="output parser")
group = parser.add_mutually_exclusive_group()
group.add_argument("--dos", help="get DOSCAR for plot",action='store_true')
parser.add_argument("-n", help="Showing last n line",
                    metavar='integer', type=int)

args = parser.parse_args()
if args.dos:
    if args.n:
        chosen = int(args.n)
        chdos = "at_dos"+str(args.n)+".dat"
    else:
        chosen = None
    inpt = "DOSY"
    print(inpt)
    print(chosen)

可以正确地产生预期的结果:

$python3 tt.py --dos
DOSY
None

$python3 tt.py --dos -n 222
DOSY
222

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