【发布时间】:2019-11-02 17:55:17
【问题描述】:
我想创建一个从 int 子类化的类,但设置一个下限和上限。
例如,如果下限是2,那么a = MyClass(1) 应该引发异常。
我很苦恼,因为int 似乎没有__init__ 函数,所以我不确定如何从它继承子类,我的尝试给了我错误。
我该怎么做呢?
【问题讨论】:
标签: python integer limit boundary bounded-types
我想创建一个从 int 子类化的类,但设置一个下限和上限。
例如,如果下限是2,那么a = MyClass(1) 应该引发异常。
我很苦恼,因为int 似乎没有__init__ 函数,所以我不确定如何从它继承子类,我的尝试给了我错误。
我该怎么做呢?
【问题讨论】:
标签: python integer limit boundary bounded-types
试试这个。它应该适用于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 子类化的难点在于它没有__init__ 函数。相反,您必须使用__new__ 函数。
BoundedNumber 类负责处理这个问题,它定义了一个 __new__ 函数,它通过调用 int(或 float)来运行 int(或 float)__new__ 函数,但也这样做之前会自行检查边界。
由于我们要动态创建一个新类,我们将不得不使用type 函数。这将允许我们在运行时创建一个具有我们想要的任何边界的新类。
从技术上讲,要回答您的问题,您只需将 BoundedNumberClassCreator 和 int 放在使用 number_class 的任何地方,但由于它也适用于 floats,所以我想我会封装减少重复代码。
如果您 ZeroToOne = BoundedInt('ZeroToOne', 0, 1) 然后创建 i = ZeroToOne(1.1) 它会抛出错误,即使 int(1.1) 在指定范围内,此解决方案的一个奇怪之处。如果你不喜欢这个功能,你可以在BoundedNumberClassCreator 的new 方法中交换检查的顺序和返回。
【讨论】:
这是直接的,没有处理多少错误。
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
【讨论】:
int 继承(例如,请参阅my answer)