Search code examples
pythonclassvalidationinheritancebase-class

How to create a class that extends the `int` base class that has input validation?


I'd like to make a class that extends the int base class, so that the object itself is an integer (i.e. you set it and read from it directly), but also has input validation - for example, only allow a given range.

From what I have researched, the __init__ method is not called when you extend normal base classes, so I'm not sure how to do this. I'm also not clear on how you access the value of the object (i.e. the actual integer assigned to it) or modify that value from within the class. I see the same issue extending any base class (string, float, tuple, list, etc.).

If I could use __init__ it would be something like:

class MyInt(int):
    def __init__(self, value):
        if value < 0 or value > 100:
            raise ValueError('MyInt objects must be in range 0-100, value was {}'.format(value))
        self = value

How can I validate new values coming into my extended int class?


Solution

  • You don't actually have to override __new__ in this case. After the object is created, __init__ will be called, and you can check if it is in range or not.

    class MyInt(int):
        def __init__(self, x, **kwargs):
            if self < 0 or self > 100:
                raise ValueError('MyInt objects must be in range 0-100, value was {}'.format(x))
    

    You can override __new__ to raise the exception before MyInt(...) returns the new object.

    class MyInt(int):
        def __new__(cls, *args, **kwargs):
            x = super().__new__(cls, *args, **kwargs)  # Let any value error propagate
            if x < 0 or x > 100:
                raise ValueError('MyInt objects must be in range 0-100, value was {}'.format(x))
            return x
    

    You might want to try to validate the argument before calling super().__new__, but strictly speaking, that's not playing well with other classes.