On Jun 22, 5:44 am, "Josip" <[EMAIL PROTECTED]> 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
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to