如何在 Python 中创建一个有界整数?
How can I create a bounded int in Python?
我想创建一个 class,它是 int
的子class,但设置了它可以是多少的下限和上限。
例如,如果下限是 2
,那么 a = MyClass(1)
应该引发异常。
我正在苦苦挣扎,因为 int
似乎没有 __init__
函数,所以我不确定如何从中提取 class,我的尝试是给我错误。
我应该怎么做?
试试这个。它应该适用于 int
s 和 float
s:
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,在运行时具有我们想要的任何边界。
从技术上讲,要回答您的问题,您只需要将 BoundedNumberClassCreator
和 int
放在使用 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
我想创建一个 class,它是 int
的子class,但设置了它可以是多少的下限和上限。
例如,如果下限是 2
,那么 a = MyClass(1)
应该引发异常。
我正在苦苦挣扎,因为 int
似乎没有 __init__
函数,所以我不确定如何从中提取 class,我的尝试是给我错误。
我应该怎么做?
试试这个。它应该适用于 int
s 和 float
s:
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,在运行时具有我们想要的任何边界。
从技术上讲,要回答您的问题,您只需要将 BoundedNumberClassCreator
和 int
放在使用 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