【问题标题】:How can I create a bounded int in Python?如何在 Python 中创建有界 int?
【发布时间】:2019-11-02 17:55:17
【问题描述】:

我想创建一个从 int 子类化的类,但设置一个下限和上限。

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

我很苦恼,因为int 似乎没有__init__ 函数,所以我不确定如何从它继承子类,我的尝试给了我错误。

我该怎么做呢?

【问题讨论】:

    标签: python integer limit boundary bounded-types


    【解决方案1】:

    试试这个。它应该适用于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 函数。这将允许我们在运行时创建一个具有我们想要的任何边界的新类。

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

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

    【讨论】:

      【解决方案2】:

      这是直接的,没有处理多少错误。

      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
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-19
      • 1970-01-01
      • 2017-04-01
      • 1970-01-01
      相关资源
      最近更新 更多