473,326 Members | 2,126 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,326 software developers and data experts.

Storing value with limits in object

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, 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?

Jun 27 '08 #1
13 1629
On Sun, Jun 22, 2008 at 11:44 AM, Josip <fa*******@noone.bewrote:
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, 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?
Not with normal vars, because = is a rebinding operator in Python,
rather than assignment.

You can do (close to) the above with object properties.

David.
Jun 27 '08 #2
Not with normal vars, because = is a rebinding operator in Python,
rather than assignment.

You can do (close to) the above with object properties.

David.
Yes, but it's done with built-in types like int and float. I suspect I could
subclass from them and implement limits, but I would have to make
seperate class for each type. Can I override conversion methods like int()
and float() within my class?
Jun 27 '08 #3
On Sun, Jun 22, 2008 at 12:24 PM, Josip <fa*******@noone.bewrote:
>Not with normal vars, because = is a rebinding operator in Python,
rather than assignment.

You can do (close to) the above with object properties.

David.

Yes, but it's done with built-in types like int and float. I suspect I could
subclass from them and implement limits, but I would have to make
seperate class for each type. Can I override conversion methods like int()
and float() within my class?
I think I may have misread your original post.

ints and floats are internal , immutable types, with some class
goodness on top (so you can treat them like objects to a degree,
subclass from them, etc). Python's interpreter has built-in logic
which 'knows' how to use ints and floats variables, without calling
their special "__" methods. Python would be a lot slower if it worked
this way.

To do exactly what you want, you'd need to add a new internal numeric
type to Python.

You can subclass from float, and redefine __float__ and __int__, but
those will only be called when your code actually calls the builtin
float() and int() builtins, eg:

import math

class Float(float):
def __float__(self):
raise NotImplementedError

a = Float(1)
print math.sin(a)

# Outputs 0.841470984808

a = Float(1)
print math.sin(float(a))

# Throws a NotImplementedError exception

There is no way (afaik) for an object to tell Python to call one of
it's methods to get a reference, or 'value' to the object (if there
was, it would make things really complicated). In Python you generally
need to update the logic used during a lookup to get that effect (ie,
in a.b.c, you can customise the a.b lookup, or the a.b.c lookup, but
not the a lookup itself).

In theory you could hack Python's internal locals or globals
dictionary so that it did something unusual while looking up your
object. But in practice this doesn't work, because the returned
objects (when you call globals() or locals()) attributes are readonly.
Probably because those internal lookup dicts are implemented in
optimized C not Python, and the C implementation doesn't let you
redefine it's internals via the Python interface.

David.
Jun 27 '08 #4
In theory you could hack Python's internal locals or globals
dictionary so that it did something unusual while looking up your
object. But in practice this doesn't work, because the returned
objects (when you call globals() or locals()) attributes are readonly.
Probably because those internal lookup dicts are implemented in
optimized C not Python, and the C implementation doesn't let you
redefine it's internals via the Python interface.

David.
I'll settle for implementing the __call__() method to return the value as I
have
no intention to mess around with Python's internal mechanisms.

Thanks a lot for your deep insight.
Jun 27 '08 #5
On Jun 22, 5:44 am, "Josip" <fake.m...@noone.bewrote:
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
Jun 27 '08 #6
Josip 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, 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?
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
Jun 27 '08 #7
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
Yes, the simple solution is often the best. 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. Storing all
the limits in caller namespace is not really an option.

Jun 27 '08 #8
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
Yes, the simple solution is often the best. 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. Storing all
the limits in caller namespace is not really an option.


Jun 27 '08 #9
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:
Actually, the version I'm using is somewhat bigger. I removed docstrings and
recklessly stripped away some methods to make it shorter concise and
incorrect.
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:
(...)

Yes, this is very close to what I was looking for. It implements all the
functionality except asssigning values. And speed is not an issue for my
application.
Thanks.

Jun 27 '08 #10
Lie
On Jun 23, 1:24*am, "Josip" <i...@i.iwrote:
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?

Try this: (_LimitedInt inherits from int, so operator overloading is
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))###
Jun 27 '08 #11
Lie
On Jun 23, 1:24*am, "Josip" <i...@i.iwrote:
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?

Try this: (_LimitedInt inherits from int, so operator overloading is
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))###
Jun 27 '08 #12
Lie
#!/usr/bin/env python

## VERSION 2
##
## changelog:
## - Uses inheritance from _Limited
## - Added _LimitedLong and llong
## - limit choose between int, long, and float

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

The lim argument accepts:
- An instance of _Limited, 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 _Limited instance is just for convenience
'''

if isinstance(lim, _Limited):
self.min, self.max = lim.limits
else:
try:
self.min, self.max = 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)

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

class _LimitedLong(long, _Limited):
def __init__(self, value, base = 10):
long.__init__(value, base)

class _LimitedFloat(float, _Limited):
def __init__(self, value):
float.__init__(value)
def lint(value, limits, base = None):
''' Always Creates _LimitedInt instance, allows the use of base
'''
if base:
ret = _LimitedInt(value, base)
else:
ret = _LimitedInt(value)

ret.limits = limits
return ret

def llong(value, limits, base = None):
''' Always Creates _LimitedLong instance, allows the use of base
'''
if base:
ret = _LimitedLong(value, base)
else:
ret = _LimitedLong(value)

ret.limits = limits
return ret

def lfloat(value, limits):
''' Always Creates _LimitedFloat instance
'''
ret = _LimitedFloat(value)

ret.limits = limits
return ret

def limit(value, limits):
''' Automatically choose between _LimitedInt, _LimitedLong,
or _LimitedFloat. Cannot use _LimitedInt's/Long's base
'''
if isinstance(value, (int, long)):
try:
ret = _LimitedInt(value)
except OverflowError:
ret = _LimitedLong(value)
elif isinstance(value, float):
ret = _LimitedFloat(value)

ret.limits = limits
return ret
Jun 27 '08 #13
Thanks alot. I'm going to use this with few modifications to tailor it to my
needs.
Thumbs up!
#!/usr/bin/env python

## VERSION 2
##
## changelog:
## - Uses inheritance from _Limited
## - Added _LimitedLong and llong
## - limit choose between int, long, and float

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

The lim argument accepts:
- An instance of _Limited, 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 _Limited instance is just for convenience
'''

if isinstance(lim, _Limited):
self.min, self.max = lim.limits
else:
try:
self.min, self.max = 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)

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

class _LimitedLong(long, _Limited):
def __init__(self, value, base = 10):
long.__init__(value, base)

class _LimitedFloat(float, _Limited):
def __init__(self, value):
float.__init__(value)
def lint(value, limits, base = None):
''' Always Creates _LimitedInt instance, allows the use of base
'''
if base:
ret = _LimitedInt(value, base)
else:
ret = _LimitedInt(value)

ret.limits = limits
return ret

def llong(value, limits, base = None):
''' Always Creates _LimitedLong instance, allows the use of base
'''
if base:
ret = _LimitedLong(value, base)
else:
ret = _LimitedLong(value)

ret.limits = limits
return ret

def lfloat(value, limits):
''' Always Creates _LimitedFloat instance
'''
ret = _LimitedFloat(value)

ret.limits = limits
return ret

def limit(value, limits):
''' Automatically choose between _LimitedInt, _LimitedLong,
or _LimitedFloat. Cannot use _LimitedInt's/Long's base
'''
if isinstance(value, (int, long)):
try:
ret = _LimitedInt(value)
except OverflowError:
ret = _LimitedLong(value)
elif isinstance(value, float):
ret = _LimitedFloat(value)

ret.limits = limits
return ret

Jun 27 '08 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

24
by: Ehud Shabtai | last post by:
Hi, I would like to store samples of data which are gathered from about 500 devices in mysql. Each device has its own data which changes over time. The data may be integer or float. The...
30
by: Alf P. Steinbach | last post by:
The C++ FAQ item 29.5 (this seems to be strongly related to C), at <url: http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.5> mentions that <quote> C++ guarantees a char is exactly one...
6
by: Alfonso Morra | last post by:
I have written the following code, to test the concept of storing objects in a vector. I encounter two run time errors: 1). myClass gets destructed when pushed onto the vector 2). Prog throws a...
12
by: Alfonso Morra | last post by:
I have the ff code for testing the concept of storing objects: #include <vector> #include <iostream> using namespace std ; class MyClass { public: MyClass(){
7
by: Dave | last post by:
I have a system that basically stores a database within a database (I'm sure lots have you have done this before in some form or another). At the end of the day, I'm storing the actual data...
6
by: (PeteCresswell) | last post by:
User wants to go this route instead of storing pointers in the DB and the documents outside. Only time I tried it was with only MS Word docs - and that was a loooong time ago - and it seemed to...
7
by: Ian Boyd | last post by:
Customer wanted us to figure out why their database was growing at an astronomical rate. We broke down the various fields making up a table, and we found that the ..LB file was using about 1k...
3
by: RSH | last post by:
Hi, I have a situation where I have created an object that contains fields,properties and functions. After creating the object I attempted to assign it to a session variable so i could retrieve...
44
by: vippstar | last post by:
n1256.pdf (C99 TC3), 5.2.4.1 Translation limits p1 says: Does that mean that *any* program using an array of two or more elements other than char is allowed to be rejected by an implementation?...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.