An extension of type int Pythons to accept only values ​​in a given range

I would like to create a custom data type that basically behaves like a regular int , but with a value limited within a given range. I think I need some kind of factory function, but I can't figure out how to do this.

 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 welcome. Thanks!

+4
source share
4 answers

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 
+5
source

An assignment in Python is an expression, not an expression, so there is no way to define an assignment for a type, since the assignment completely rewrites the name. The best you can do is define a set() method that takes the required value, after which you can simply create a "normal" class to handle the validation.

+1
source

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 
+1
source

You can get the class from int in python, for example. class MyInt(int) , but this type in python is immutable (you cannot change the value) after creating it.

You could do something like this:

 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 eg addition etc operations to the integer # Beware that eg 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’s better to use the usual validation functions depending on what you want, but if it's easier.

EDIT : working now - reverting to a simpler earlier version, having add functions, etc. that return other instances of MyInt, is simply not worth it :-)

0
source

Source: https://habr.com/ru/post/1306881/


All Articles