开发者

Extending Python’s int type to accept only values within a given range

I would like to create a custom data type whi开发者_高级运维ch basically behaves like an ordinary int, but with the value restricted to be within a given range. I guess I need some kind of factory function, but I cannot figure out how to do it.

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

Any hint is appreciated. Thanks!


Use __new__ to override the construction of immutable types:

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


Assignment in Python is a statement, not an expression, therefore there's no way to define assignment on a type since assigning rebinds the name completely. The best you could do is define a set() method that takes the value that you want, at which point you can just create a "normal" class to handle the validation.


There is no need to define a new type:

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

Example

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


You can derive a class from an int in python e.g. class MyInt(int), but that type in python is immutable (you can't change the value) once it's created.

You could do something like this though:

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

It may be better to use ordinary validation functions depending on what you want though if it's simpler.

EDIT: Is working now - Reverted back to a simpler earlier version, having addition etc functions which return other MyInt instances just isn't worth it :-)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜