如何在 Python 中创建一个有界整数?

How can I create a bounded int in Python?

我想创建一个 class,它是 int 的子class,但设置了它可以是多少的下限和上限。

例如,如果下限是 2,那么 a = MyClass(1) 应该引发异常。

我正在苦苦挣扎,因为 int 似乎没有 __init__ 函数,所以我不确定如何从中提取 class,我的尝试是给我错误。

我应该怎么做?

试试这个。它应该适用于 ints 和 floats:

def BoundedNumber(number_class):
    def BoundedNumberClassCreator(class_name, lower_bound, upper_bound):
        if upper_bound and lower_bound and upper_bound < lower_bound:
            raise ValueError(f"Upper bound {upper_bound} is lower than the lower bound {lower_bound}")

        def new(cls, number):
            if lower_bound and number < lower_bound:
                raise ValueError(f"{number} is below the lower bound of {lower_bound} for this class")

            if upper_bound and upper_bound < number:
                raise ValueError(f"{number} is above the upper bound of {upper_bound} for this class")

            return number_class(number)

        return type(class_name, (number_class,),
                    {"__new__": new,
                     "__doc__": f"Class that acts like `{number_class.__name__}` but has an inclusive lower bound of {lower_bound} and an inclusive upper bound of {upper_bound}",
                     "lower_bound": lower_bound,
                     "upper_bound": upper_bound})

    return BoundedNumberClassCreator

BoundedInt = BoundedNumber(int)
BoundedFloat = BoundedNumber(float)

if __name__ == "__main__":
    IntBetween50And150 = BoundedInt('IntBetween50And150', 50, 150)
    print(IntBetween50And150(100) == 100)  # True
    try:
        IntBetween50And150(200)
    except ValueError as e:
        print(f"Caught the ValueError: {e}")  # Caught the value error: 200 is above the upper bound of 150 for this class

    print(IntBetween50And150(50.5))  # 50
    print(IntBetween50And150.__doc__) # Class that acts like `int` but has an inclusive lower bound of 50 and an inclusive upper bound of 150

int 使用 subclass 的难点在于它没有 __init__ 功能。相反,您必须使用 __new__ 函数。

BoundedNumber class 负责处理这个问题,定义了一个 __new__ 函数,它同时运行 int(或 float__new__ 函数通过调用 int(或 float),但也会在这样做之前运行自己的边界检查。

由于我们要动态创建一个新的 class,我们将不得不使用 type 函数。这将允许我们创建一个新的class,在运行时具有我们想要的任何边界。

从技术上讲,要回答您的问题,您只需要将 BoundedNumberClassCreatorint 放在使用 number_class 的任何地方,但因为它适用于 float同样,我想我会封装它以减少重复代码。

如果您 ZeroToOne = BoundedInt('ZeroToOne', 0, 1) 然后创建 i = ZeroToOne(1.1),此解决方案有一点奇怪,即使 int(1.1) 在指定范围内,它也会抛出错误。如果你不喜欢这个功能,你可以交换检查的顺序和 BoundedNumberClassCreator.

new 方法中的 return

这是即时的,没有处理多少错误。

class boundedInt:

    def __init__(self, lower, upper):
        self.x = None
        if (lower <= upper):
            self.lower = lower
            self.upper = upper
        else:
            raise ValueError("Lower Bound must be lesser than Upper Bound".format())  

    def assign(self, x):
        if (x>= self.lower and x<=self.upper):
            self.x = x
            return self.x
        else:
            raise ValueError("Not in bounds")

myInt = boundedInt(15,20) # create object myInt
f = myInt.assign(17) # assigns value to a variable