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)

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

    def __radd__(self, other): return self._apply(operator.add, other,
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



More information about the Python-list mailing list