# Storing value with limits in object

George Sakkis george.sakkis at gmail.com
Sun Jun 22 15:36:51 CEST 2008

```On Jun 22, 5:44 am, "Josip" <fake.m... at noone.be> wrote:

> I'm trying to limit a value stored by object (either int or float):
>
> class Limited(object):
>     def __init__(self, value, min, max):
>         self.min, self.max = min, max
>         self.n = value
>     def set_n(self,value):
>         if value < self.min: # boundary check
>             self.n = self.min
>         if value > self.max:
>             self.n = self.max
>         else:
>             self.n = value
>     n = property(lambda self : self._value, set_n)
>
> This works,

I bet you didn't even try this, unless your definition of "works"
includes a "RuntimeError: maximum recursion depth exceeded". Here's a
a working version:

class Limited(object):
def __init__(self, value, min, max):
self.min, self.max = min, max
self.n = value

n = property(lambda self : self._value,
lambda self,value:
self.__dict__.__setitem__('_value',
max(self.min, min(value,
self.max))))

def __int__(self): return int(self._value)
def __float__(self): return float(self._value)

a = Limited(11, 0, 9)
print float(a)
import math
print math.sqrt(a)

> except I would like the class to behave like built-in types, so
> I can use it like this:
>
> a = Limited(7, 0, 10)
> b = math.sin(a)
>
> So that object itself returns it's value (which is stored in a.n). Is this
> possible?

For (most) math.* functions it suffices to define __float__, so the
above works. For making it behave (almost) like a regular number,
you'd have to write many more special methods: http://docs.python.org/ref/numeric-types.html.
Here's a possible start:

import operator

class Limited(object):
def __init__(self, value, min, max):
self.min, self.max = min, max
self.n = value

n = property(lambda self : self._value,
lambda self,value:
self.__dict__.__setitem__('_value',
max(self.min, min(value,
self.max))))

def __str__(self): return str(self.n)
def __repr__(self): return 'Limited(%r, min=%r, max=%r)' %
(self.n, self.min, self.max)

def __int__(self): return int(self._value)
def __float__(self): return float(self._value)

other)
def __sub__(self, other): return self._apply(operator.sub, self,
other)
# a few dozens more methods follow ...

self)
def __rsub__(self, other): return self._apply(operator.sub, other,
self)
# a few dozens more methods follow ...

@classmethod
def _apply(cls, op, first, second):
minmax = None
if isinstance(first, cls):
minmax = first.min,first.max
first = first._value
if isinstance(second, cls):
if minmax is None:
minmax = second.min,second.max
second = second._value
return cls(op(first,second), *minmax)

a = Limited(11, 0, 9)
print a+1
print 1+a
print a-1
print 1-a

Needless to say, this is almost two orders of magnitude slower than
the builtin numbers, so you'd better not use it for any serious number
crunching.

HTH,
George

```