# Storing value with limits in object

Lie Lie.1296 at gmail.com
Mon Jun 23 23:25:49 CEST 2008

```On Jun 23, 1:24 am, "Josip" <i... at i.i> wrote:
> > Why not make it a function?
>
> > function assignLimited(value, vmin, vmax):
> >     value = max(vmin, value)
> >     value = min(vmax, value)
> >     return value
>
> > a = assignLimited(7, 0, 10)
>
> > Seems like it solves your problem relatively cleanly.
> > Note: I also removed min/max variables because they would mask the
> > built-in min/max functions.
>
> > -Larry
>

> Still, I'm going for object
> oriented solution because I want the value and it's limits to be kept
> together as I'll have many such values with different limits.

In that case, "overriding assignment" makes no sense since if an
operation is done on two values that have two different limits, what
would happen? Take the first's or second's limits, or interpolate the
new limit by some magic function? A much better solution would be for
operation to always return plain vanilla int, and we set limits
explicitly.

> Storing all
> the limits in caller namespace is not really an option.

You want to store limits in the object too?

unnecessary)

###
#!/usr/bin/env python

class _LimitedInt(int):
class InvalidLimitsError(Exception): pass

def __init__(self, value, base = 10):
int.__init__(value, base)

def setlimits(self, lim):
''' Set the limits and if value is not within limit,
raise ValueError

The lim argument accepts:
- A _LimitedInt instance, from which to copy the limits
- A two-tuple, which specifies the limits i.e. (min, max)

If lim isn't those or lim[0] > lim[1], raise
InvalidLimitsError

Accepting _LimitedInt instance is just for convenience
'''

if isinstance(lim, _LimitedInt):
lim = lim.limits

try:
self.min, self.max = [int(x) for x in lim]
if self.min > self.max: raise ValueError
except (ValueError, TypeError):
raise self.InvalidLimitsError, ('limit = %s' % str(lim))

if not (self.min < self < self.max):
raise ValueError, \
('val = %s, min = %s, max = %s' % \
(self, self.min, self.max))

def getlimits(self):
return (self.min, self.max)

limits = property(getlimits, setlimits)

def lint(value, limits, base = 10):
if base != 10:
ret = _LimitedInt(value, base)
else:
ret = _LimitedInt(value)

ret.limits = limits
return ret

###         END OF REAL CODE        ###
### THE REST ARE JUST TESTING CODES ###

if __name__ == '__main__':
print 'Instantiating lint...'
a = lint(50, (0, 200))  # Limit explicitly specified
b = lint(150, a)        # Copy the limits of a
c = lint(a, (0, 1000))  # Value = a, Limit = (0, 1000)
d = lint(a, c)          # Value = a, Limit = c
print

print 'Printing the value and the limits...'
print a, a.limits
print b, b.limits
print c, c.limits
print d, d.limits
print

print 'Changing limits'
print 'Note: lint is partially immutable,'
print '      its limits is mutable,'
print '      while its value is immutable'
a.limits = (0, 300)
b.limits = a
print a, a.limits
print b, b.limits
print

print '"Changing" values'
a = lint(b, a)
print a, a.limits
print

print 'Operations...'
e = lint(a + b - c * d + 100, (-10000, 1000))
f = a + b - c * d              ## Operation returns plain integer
g = lint(f, (-100000, 100000)) ## Always recast result of operator
print e, e.limits, type(e)     ## This is an int, not lint
print f, type(f)               ## BEWARE: f is integer, it has no
limits
print g, g.limits, type(g)

## INVALIDS
# a = lint(100, (1000, 100000))
# a = lint(100, 'ab')
# a = lint(100, (10000, 0))
# a = lint(100, 10)
# a = lint(100, (10, 1000, 10000))###

```