如何使用argparse指定最小或最大浮点值

10

我如何使用argparse指定浮点数参数的最小值或最大值?我希望能够在最小值和最大值之间提供命令行参数。

我能找到的最接近的选项是add_argument()中的choices选项,但这只指定了参数的可允许值。

parser.add_argument("L", type=float, choices=range(2))
命令行参数0.5无法满足L的要求:
invalid choice: 0.5 (choose from 0, 1)

编写自己的 type 函数。 - hpaulj
这个回答解决了你的问题吗?Python argparse整数条件(>=12) - A.Casanova
4个回答

16

你可以(而且应该)使用自定义类型函数。这样更加用户友好。

def range_limited_float_type(arg):
    """ Type function for argparse - a float within some predefined bounds """
    try:
        f = float(arg)
    except ValueError:    
        raise argparse.ArgumentTypeError("Must be a floating point number")
    if f < MIN_VAL or f > MAX_VAL:
        raise argparse.ArgumentTypeError("Argument must be < " + str(MAX_VAL) + "and > " + str(MIN_VAL))
    return f



parser.add_argument(
    '-f',
    '--float',
    type=range_limited_float_type,
    help='Your argument description'
)

12

解决方案

基于@rdas的精彩解决方案,我创建了一个新的解决方案,允许动态指定应该由ArgumentParser检查的浮点范围。

代码

import argparse

def float_range(mini,maxi):
    """Return function handle of an argument type function for 
       ArgumentParser checking a float range: mini <= arg <= maxi
         mini - minimum acceptable argument
         maxi - maximum acceptable argument"""

    # Define the function with default arguments
    def float_range_checker(arg):
        """New Type function for argparse - a float within predefined range."""

        try:
            f = float(arg)
        except ValueError:    
            raise argparse.ArgumentTypeError("must be a floating point number")
        if f < mini or f > maxi:
            raise argparse.ArgumentTypeError("must be in range [" + str(mini) + " .. " + str(maxi)+"]")
        return f

    # Return function handle to checking function
    return float_range_checker

如何使用

您可以在ArgumentParser中将此函数用作动态参数类型生成器:

parser = ArgumentParser(description='%(prog)s: My programm')
parser.add_argument('--Temperature', type=float_range(8,25), 
                        help='Set target temperature between [8°C .. 25°C].')

工作原理

float_range(mini,maxi)函数创建一个本地上下文环境,其中minimaxi是已知的变量。在此上下文中定义float_range_checker()函数并返回其句柄。当ArgumentParser调用此函数句柄时,将还原使用float_range()调用时提供的值的上下文,并进行范围检查。


3

受到已有答案的启发,这里提供一个更通用的解决方案,适用于从字符串输入创建的所有类型,并带有工作的"<"和">"运算符:

def ranged_type(value_type, min_value, max_value):
    """
    Return function handle of an argument type function for ArgumentParser checking a range:
        min_value <= arg <= max_value

    Parameters
    ----------
    value_type  - value-type to convert arg to
    min_value   - minimum acceptable argument
    max_value   - maximum acceptable argument

    Returns
    -------
    function handle of an argument type function for ArgumentParser


    Usage
    -----
        ranged_type(float, 0.0, 1.0)

    """

    def range_checker(arg: str):
        try:
            f = value_type(arg)
        except ValueError:
            raise argparse.ArgumentTypeError(f'must be a valid {value_type}')
        if f < min_value or f > max_value:
            raise argparse.ArgumentTypeError(f'must be within [{min_value}, {min_value}]')
        return f

    # Return function handle to checking function
    return range_checker

示例

您可以将其用于浮点数和整数,但不仅限于此:

parser.add_argument('--float_example',
                    type=ranged_type(float, 0.0, 1.0))
parser.add_argument('--int_example',
                    type=ranged_type(int, -5, 5))

甚至可以与字符串一起使用

parser.add_argument('--str_example',
                    type=ranged_type(str, "a", "d"))

测试

一个小型测试/概念验证:

parser = argparse.ArgumentParser(prog='argtest')
parser.add_argument('--float_example',
                    type=ranged_type(float, 0.0, 1.0))
parser.add_argument('--int_example',
                    type=ranged_type(int, -5, 5))
parser.add_argument('--str_example',
                    type=ranged_type(str, "a", "d"))

print(parser.parse_args())

以下是相应的结果:

> python argtest.py --float_example 0.5 --str_example b --int_example 4

Namespace(float_example=0.5, int_example=4, str_example='b')


> python argtest.py --float_example -0.5

usage: argtest [-h] [--float_example FLOAT_EXAMPLE] [--int_example INT_EXAMPLE] [--str_example STR_EXAMPLE]
argtest: error: argument --float_example: must be within [0.0, 1.0]


> python argtest.py --int_example 12    

usage: argtest [-h] [--float_example FLOAT_EXAMPLE] [--int_example INT_EXAMPLE] [--str_example STR_EXAMPLE]
argtest: error: argument --int_example: must be within [-5, 5]


> python argtest.py --str_example g 

usage: argtest [-h] [--float_example FLOAT_EXAMPLE] [--int_example INT_EXAMPLE] [--str_example STR_EXAMPLE]
argtest: error: argument --str_example: must be within [a, d]



3
在进行了一些尝试后,最简单的答案是在argparse之外处理命令行输入的最小或最大值的验证。这样可以编写一个函数和条件来检查浮点值。如果条件得到满足,则退出程序:
import sys

# function to print error to stderr
def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs

# input validation
if args.L <=0:
    eprint("Input error. Length is less than 0. Please enter a positive length. Exiting.")
    sys.exit(1)

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