【问题标题】:Extending Python’s int type to accept only values within a given range扩展 Python 的 int 类型以仅接受给定范围内的值
【发布时间】:2010-04-14 05:48:20
【问题描述】:

我想创建一个自定义数据类型,它的行为基本上类似于普通的int,但其值限制在给定范围内。我想我需要某种工厂函数,但我不知道该怎么做。

myType = MyCustomInt(minimum=7, maximum=49, default=10)
i = myType(16)    # OK
i = myType(52)    # raises ValueError
i = myType()      # i == 10

positiveInt = MyCustomInt(minimum=1)     # no maximum restriction
negativeInt = MyCustomInt(maximum=-1)    # no minimum restriction
nonsensicalInt = MyCustomInt()           # well, the same as an ordinary int

感谢任何提示。谢谢!

【问题讨论】:

    标签: python types


    【解决方案1】:

    使用__new__ 覆盖不可变类型的构造:

    def makeLimitedInt(minimum, maximum, default):
        class LimitedInt(int):
            def __new__(cls, x= default, *args, **kwargs):
                instance= int.__new__(cls, x, *args, **kwargs)
                if not minimum<=instance<=maximum:
                    raise ValueError('Value outside LimitedInt range')
                return instance
        return LimitedInt
    

    【讨论】:

    • 您的解决方案忽略了default
    • 哎呀,是的,在弄乱 args 时意外删除。重新添加。
    【解决方案2】:

    Python 中的赋值是一个语句,而不是一个表达式,因此无法在类型上定义赋值,因为赋值会完全重新绑定名称。您可以做的最好的事情是定义一个 set() 方法来获取您想要的值,此时您可以创建一个“普通”类来处理验证。

    【讨论】:

      【解决方案3】:

      无需定义新类型:

      def restrict_range(minimum=None, maximum=None, default=None, type_=int):
          def restricted(*args, **kwargs):
              if default is not None and not (args or kwargs): # no arguments supplied
                  return default
              value = type_(*args, **kwargs)
              if (minimum is not None and value < minimum or 
                  maximum is not None and value > maximum):
                  raise ValueError
              return value
          return restricted
      

      示例

      restricted_int = restrict_range(7, 49, 10)
      
      assert restricted_int("1110", 2) == 14
      assert restricted_int(16) == 16
      assert restricted_int() == 10
      try: 
          restricted_int(52)
          assert 0
      except ValueError:
          pass
      

      【讨论】:

        【解决方案4】:

        您可以从 python 中的int 派生一个类,例如class MyInt(int),但是 python 中的类型在创建后是不可变的(您无法更改值)。

        你可以这样做:

        class MyInt:
            def __init__(self, i, max=None, min=None):
                self.max = max
                self.min = min
                self.set(i)
        
            def set(self, i):
                if i > self.max: raise ValueError
                if i < self.min: raise ValueError
                self.i = i
        
            def toInt(self):
                return self.i
        
            def __getattr__(self, name):
                # Forward e.g. addition etc operations to the integer
                #   Beware that e.g. going MyInt(1)+MyInt(1) 
                #   will return an ordinary int of "2" though
                #   so you'd need to do something like 
                #   "result = MyInt(MyInt(1)+MyInt(1))
        
                method = getattr(self.i, name)
                def call(*args):
                    L = []
                    for arg in args:
                        if isinstance(arg, MyInt):
                            L.append(arg.toInt())
                        else: L.append(arg)
                    return method(*L)
                return call
        

        根据您的需要使用普通的验证函数可能会更好,但如果它更简单的话。

        编辑:现在正在工作 - 恢复到更简单的早期版本,具有返回其他 MyInt 实例的附加等函数是不值得的 :-)

        【讨论】:

        • # Beware that e.g. going MyInt(1)+MyInt(1) will return an ordinary int of "2" though 如果你不是 return MyInt(getattr(self.i, name), max, min) :)
        • @bp:这行不通,因为getattr() 返回的是一个函数而不是一个整数。稍后可以返回一个将结果转换为 MyInt 的函数,你是对的!
        猜你喜欢
        • 2022-01-09
        • 2020-01-12
        • 2022-12-06
        • 2017-06-29
        • 2011-10-29
        • 1970-01-01
        • 2022-01-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多