在Python中,使用argparse时只允许正整数

68bkxrlz  于 2022-12-10  发布在  Python
关注(0)|答案(6)|浏览(152)

标题几乎概括了我希望发生的事情。
下面是我的结果,虽然程序不会因为非正整数而崩溃,但我希望用户知道,非正整数基本上是没有意义的。

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-g", "--games", type=int, default=162,
                    help="The number of games to simulate")
args = parser.parse_args()

而输出:

python simulate_many.py -g 20
Setting up...
Playing games...
....................

输出带负数:

python simulate_many.py -g -2
Setting up...
Playing games...

现在,显然我可以添加一个if来确定if args.games为负,但我很好奇是否有一种方法可以在argparse级别捕获它,以便利用自动使用打印。
理想情况下,它将打印类似于以下内容的内容:

python simulate_many.py -g a
usage: simulate_many.py [-h] [-g GAMES] [-d] [-l LEAGUE]
simulate_many.py: error: argument -g/--games: invalid int value: 'a'

就像这样:

python simulate_many.py -g -2
usage: simulate_many.py [-h] [-g GAMES] [-d] [-l LEAGUE]
simulate_many.py: error: argument -g/--games: invalid positive int value: '-2'

现在我在做这个,我想我很高兴:

if args.games <= 0:
    parser.print_help()
    print "-g/--games: must be positive."
    sys.exit(1)
z31licg0

z31licg01#

利用type应该可以做到这一点。您仍然需要定义一个实际的方法来决定这一点:

def check_positive(value):
    ivalue = int(value)
    if ivalue <= 0:
        raise argparse.ArgumentTypeError("%s is an invalid positive int value" % value)
    return ivalue

parser = argparse.ArgumentParser(...)
parser.add_argument('foo', type=check_positive)

这基本上只是argparse文档中perfect_square函数的一个改编示例。

lrpiutwd

lrpiutwd2#

type是处理条件/检查的推荐选项,如Yuushi的回答所示。
在您的特定情况下,如果上限也是已知的,也可以使用choices参数:

parser.add_argument('foo', type=int, choices=xrange(5, 10))

**注意:**对于python 3.x,请使用range而不是xrange

aij0ehis

aij0ehis3#

如果您的arg有一个可预测的max和min,那么最快捷的方法就是使用带有range的choices

parser.add_argument('foo', type=int, choices=xrange(0, 1000))
csbfibhn

csbfibhn4#

一个更简单的替代方法是从parse_args方法内部启动验证,尤其是在对argparse.ArgumentParser进行子类化时。
在这样的子类内:

def parse_args(self, args=None, namespace=None):
    """Parse and validate args."""
    namespace = super().parse_args(args, namespace)
    if namespace.games <= 0:
         raise self.error('The number of games must be a positive integer.')
    return namespace

这种技术可能没有自定义可调用对象那么酷,但它确实起作用了。
关于ArgumentParser.error(message)
这个方法会打印包含标准错误消息的使用方式消息,并以状态码2结束程式。
贷方:answer by jonatan

icnyk63a

icnyk63a5#

如果有人(像我一样)在Google搜索中遇到这个问题,这里有一个例子,说明如何使用模块化方法巧妙地解决更普遍的问题,即只允许在指定范围内使用argparse整数。

# Custom argparse type representing a bounded int
class IntRange:

    def __init__(self, imin=None, imax=None):
        self.imin = imin
        self.imax = imax

    def __call__(self, arg):
        try:
            value = int(arg)
        except ValueError:
            raise self.exception()
        if (self.imin is not None and value < self.imin) or (self.imax is not None and value > self.imax):
            raise self.exception()
        return value

    def exception(self):
        if self.imin is not None and self.imax is not None:
            return argparse.ArgumentTypeError(f"Must be an integer in the range [{self.imin}, {self.imax}]")
        elif self.imin is not None:
            return argparse.ArgumentTypeError(f"Must be an integer >= {self.imin}")
        elif self.imax is not None:
            return argparse.ArgumentTypeError(f"Must be an integer <= {self.imax}")
        else:
            return argparse.ArgumentTypeError("Must be an integer")

这允许您执行以下操作:

parser = argparse.ArgumentParser(...)
parser.add_argument('foo', type=IntRange(1))     # Must have foo >= 1
parser.add_argument('bar', type=IntRange(1, 7))  # Must have 1 <= bar <= 7

变量foo现在只允许正整数,就像OP要求的那样。
请注意,除了上述形式之外,IntRange也可以仅为最大值:

parser.add_argument('other', type=IntRange(imax=10))  # Must have other <= 10
pxq42qpu

pxq42qpu6#

根据Yuushi的答案,您还可以定义一个简单的helper函数,它可以检查一个数字对于各种数值类型是否为正数:

def positive(numeric_type):
    def require_positive(value):
        number = numeric_type(value)
        if number <= 0:
            raise ArgumentTypeError(f"Number {value} must be positive.")
        return number

    return require_positive

helper函数可用于注解任何数值参数类型,如下所示:

parser = argparse.ArgumentParser(...)
parser.add_argument("positive-integer", type=positive(int))
parser.add_argument("positive-float", type=positive(float))

相关问题