Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > subclass of integers

Reply
Thread Tools

subclass of integers

 
 
Mark Morss
Guest
Posts: n/a
 
      09-14-2007
I would like to construct a class that includes both the integers and
None. I desire that if x and y are elements of this class, and both
are integers, then arithmetic operations between them, such as x+y,
return the same result as integer addition. However if either x or y
is None, these operations return None.

It's simple enough to construct a subclass of integers that behave in
this way:

class Nint(int):
def __add__(self,other):
if (other != None):
return self+other
else:
return None
def __radd__(self,other):
if (other != None):
return other+self
else:
return None
#...and so forth

However I have not been able to figure out how to make it so that
None, as well as an integer, could be an element of my class. My
preliminary impression is that I have to override int.__new__; but I
am uncertain how to do that and have been unable to find anything on
the web explaining that. Indeed I haven't been able to find much
about __new__ at all. Overriding this method of built-in classes
seems to be quite unusual.

I would very much appreciate anyone's help.

 
Reply With Quote
 
 
 
 
Mark Morss
Guest
Posts: n/a
 
      09-14-2007
On Sep 14, 10:30 am, Mark Morss <(E-Mail Removed)> wrote:
> I would like to construct a class that includes both the integers and
> None. I desire that if x and y are elements of this class, and both
> are integers, then arithmetic operations between them, such as x+y,
> return the same result as integer addition. However if either x or y
> is None, these operations return None.
>
> It's simple enough to construct a subclass of integers that behave in
> this way:
>
> class Nint(int):
> def __add__(self,other):
> if (other != None):
> return self+other
> else:
> return None
> def __radd__(self,other):
> if (other != None):
> return other+self
> else:
> return None
> #...and so forth
>
> However I have not been able to figure out how to make it so that
> None, as well as an integer, could be an element of my class. My
> preliminary impression is that I have to override int.__new__; but I
> am uncertain how to do that and have been unable to find anything on
> the web explaining that. Indeed I haven't been able to find much
> about __new__ at all. Overriding this method of built-in classes
> seems to be quite unusual.
>
> I would very much appreciate anyone's help.


I meant of course that arithmetic operations between integer elements
would return the same result as the corresponding integer operations,
not necessarily addition.

 
Reply With Quote
 
 
 
 
Zentrader
Guest
Posts: n/a
 
      09-14-2007
I would do something along the lines of the following, although it
only tests for integers and not floats, so would return 'None' for a
float.

class Nint(int):
def __add__(self, x, y):
if isinstance(x, int) and isinstance(y, int):
return x+y
return None

if __name__=='__main__':
N=Nint()
print N.__add__( 1, 2 )
print N.__add__( 1, None )

 
Reply With Quote
 
Zentrader
Guest
Posts: n/a
 
      09-14-2007
This would accept ints, floats, and decimal types.

import decimal

class Nint(int):
def __add__(self, x, y):
try:
return x+y
except:
return None

if __name__=='__main__':
N=Nint()
print N.__add__( 1, 2 )
print N.__add__( 1, None )
print N.__add__(decimal.Decimal("2"), decimal.Decimal("3"))
print N.__add__(decimal.Decimal("2"), 3)

 
Reply With Quote
 
Michael Spencer
Guest
Posts: n/a
 
      09-14-2007
Mark Morss wrote:
> I would like to construct a class that includes both the integers and
> None. I desire that if x and y are elements of this class, and both
> are integers, then arithmetic operations between them, such as x+y,
> return the same result as integer addition. However if either x or y
> is None, these operations return None.
>
> It's simple enough to construct a subclass of integers that behave in
> this way:
>
> class Nint(int):
> def __add__(self,other):
> if (other != None):
> return self+other
> else:
> return None
> def __radd__(self,other):
> if (other != None):
> return other+self
> else:
> return None
> #...and so forth
>
> However I have not been able to figure out how to make it so that
> None, as well as an integer, could be an element of my class. My
> preliminary impression is that I have to override int.__new__; but I
> am uncertain how to do that and have been unable to find anything on
> the web explaining that. Indeed I haven't been able to find much
> about __new__ at all. Overriding this method of built-in classes
> seems to be quite unusual.
>
> I would very much appreciate anyone's help.
>

Do you really need to define one class that can represent None and the integers?
integers already behave as you want, except that they cannot do binary
operations with None. So why not simply define a NoneInt object?

>>> class NoneInt(object):

... def _all_binops(self, other):
... if isinstance(other, (int, NoneInt)):
... return NoneInt()
... else:
... raise TypeError()
... __add__ = __radd__ = _all_binops
... # ...add comparison, unary methods to taste
... def __repr__(self):
... return "NoneInt()"
...
>>> 3+NoneInt()

NoneInt()
>>> NoneInt()+2

NoneInt()
>>> "s"+NoneInt()

Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 6, in _all_binops
TypeError
>>>


Getting back to your question, you can indeed override int.__new__ to return
something other than a raw int. This explains how and why:
http://www.python.org/download/relea....3/descrintro/
But unless there's more to your requirement than you set out above, it's
probably not worth the trouble.

HTH, Michael



 
Reply With Quote
 
Ian Clark
Guest
Posts: n/a
 
      09-14-2007
Mark Morss wrote:
> I would like to construct a class that includes both the integers and
> None. I desire that if x and y are elements of this class, and both
> are integers, then arithmetic operations between them, such as x+y,
> return the same result as integer addition. However if either x or y
> is None, these operations return None.
>
> It's simple enough to construct a subclass of integers that behave in
> this way:
>
> class Nint(int):
> def __add__(self,other):
> if (other != None):
> return self+other
> else:
> return None
> def __radd__(self,other):
> if (other != None):
> return other+self
> else:
> return None
> #...and so forth
>
> However I have not been able to figure out how to make it so that
> None, as well as an integer, could be an element of my class. My
> preliminary impression is that I have to override int.__new__; but I
> am uncertain how to do that and have been unable to find anything on
> the web explaining that. Indeed I haven't been able to find much
> about __new__ at all. Overriding this method of built-in classes
> seems to be quite unusual.
>
> I would very much appreciate anyone's help.


My thought would be rather than trying to cram None into a subclass of
int, to use delegation instead...

-----8<--------------------------------------------------
class NoneInt(object):
def __init__(self, value):
self.value = value

def __add__(self, other):
if isinstance(other, NoneInt):
if None in (self.value, other.value):
return NoneInt(None)
return NoneInt(self.value + other.value)
elif isinstance(other, int):
if self.value is None:
return NoneInt(None)
return NoneInt(self.value + other)
else:
raise TypeError(
"unsupported operand type(s) for +: 'NoneInt'"
"and '%s'" % str(other.__class__.__name__)
)
__radd__ = __add__

def __str__(self):
return 'NoneInt(%s)' % str(self.value)


def main():
print '42? ', NoneInt(40) + NoneInt(2)
print '41? ', NoneInt(40) + 1
print '40? ', 25 + NoneInt(15)
print 'None? ', NoneInt(None)
print 'None? ', NoneInt(None) + 1
print 'None? ', 1 + NoneInt(None)
print 'Error? ', NoneInt(0) + 'spam'

if __name__ == '__main__':
main()
-----8<--------------------------------------------------

Ian

 
Reply With Quote
 
Ian Clark
Guest
Posts: n/a
 
      09-14-2007
Ian Clark wrote:
> Mark Morss wrote:
>> I would like to construct a class that includes both the integers and
>> None. I desire that if x and y are elements of this class, and both
>> are integers, then arithmetic operations between them, such as x+y,
>> return the same result as integer addition. However if either x or y
>> is None, these operations return None.
>>
>> (snip)
>>
>> I would very much appreciate anyone's help.

>
> My thought would be rather than trying to cram None into a subclass of
> int, to use delegation instead...
>
> (snip)
>
> Ian


A more robust implementation that accounts for ints/longs as well as
implementing more operations...

-----8<--------------------------------------------------
import operator

class NoneInt(object):
_LEFT = 1
_RIGHT = 2


def __init__(self, value):
self.value = value


def _get_arguments(self, other, direction=_LEFT):
""" Given a direction (left or right), returns the left hand
side and right hand side values. """

if direction == self._LEFT:
lhs = self.value
if isinstance(other, (int, long, type(None))):
rhs = other
else:
rhs = other.value
elif direction == self._RIGHT:
rhs = self.value
if isinstance(other, (int, long, type(None))):
lhs = other
else:
lhs = other.value
else:
raise ValueError('direction must be either _LEFT or _RIGHT')
return (lhs, rhs)


def _operation(op, direction):
""" Given a direction and an operation will return a function
that calls the operation with the arguments in the correct
order. """

def func(self, other):
if not isinstance(other, (int, long, NoneInt, type(None))):
fmt = "unsupported operand type(s) for %s: 'NoneInt'
and '%s'"
args = (op.__name__, other.__class__.__name__)
raise TypeError(fmt % args)

lhs, rhs = self._get_arguments(other, direction)

if None in (lhs, rhs):
return NoneInt(None)
return NoneInt(op(lhs, rhs))
return func


__add__ = _operation(operator.add, _LEFT)
__radd__ = _operation(operator.add, _RIGHT)
__sub__ = _operation(operator.sub, _LEFT)
__rsub__ = _operation(operator.sub, _RIGHT)
__div__ = _operation(operator.div, _LEFT)
__rdiv__ = _operation(operator.div, _RIGHT)
__mul__ = _operation(operator.mul, _LEFT)
__rmul__ = _operation(operator.mul, _RIGHT)
# ... etc


def __eq__(self, other):
lhs, rhs = self._get_arguments(other)
return lhs == rhs


def __nonzero__(self):
return bool(self.value)


def __str__(self):
return 'NoneInt(%s)' % str(self.value)

__repr__ = __str__
-----8<--------------------------------------------------

Ian

 
Reply With Quote
 
Dan Bishop
Guest
Posts: n/a
 
      09-14-2007
On Sep 14, 9:30 am, Mark Morss <(E-Mail Removed)> wrote:
> I would like to construct a class that includes both the integers and
> None. I desire that if x and y are elements of this class, and both
> are integers, then arithmetic operations between them, such as x+y,
> return the same result as integer addition. However if either x or y
> is None, these operations return None.


Rather than subclassing int, why not just make a singleton NaN object
with overloaded arithmetic operators that all return NaN?

 
Reply With Quote
 
Gabriel Genellina
Guest
Posts: n/a
 
      09-15-2007
En Fri, 14 Sep 2007 20:16:36 -0300, Dan Bishop <(E-Mail Removed)>
escribi�:

> On Sep 14, 9:30 am, Mark Morss <(E-Mail Removed)> wrote:
>> I would like to construct a class that includes both the integers and
>> None. I desire that if x and y are elements of this class, and both
>> are integers, then arithmetic operations between them, such as x+y,
>> return the same result as integer addition. However if either x or y
>> is None, these operations return None.

>
> Rather than subclassing int, why not just make a singleton NaN object
> with overloaded arithmetic operators that all return NaN?


Like this:

class _NaN(object):

__instance = None

def __new__(cls):
if cls.__instance is None:
cls.__instance = super(_NaN, cls).__new__(cls)
return cls.__instance

__repr__ = __str__ = lambda self: 'NaN'

def unop(self): return self
def binop(self, other): return self
def terop(self, other, unused=None): return self
def false2(self, other): return False
def true2(self, other): return True
def notimpl(self): return NotImplemented

__abs__ = __invert__ = __neg__ = __pos__ = unop
__add__ = __and__ = __div__ = __divmod__ = __floordiv__ = __lshift__ =
__mod__ = __mul__ = __rshift__ = __or__ = __sub__ = __truediv__ = __xor__
= binop
__radd__ = __rand__ = __rdiv__ = __rdivmod__ = __rfloordiv__ =
__rlshift__ = __rmod__ = __rmul__ = __rpow__ = __rrshift__ = __ror__ =
__rsub__ = __rtruediv__ = __rxor__ = binop
__pow__ = terop
__lt__ = __le__ = __eq__ = __gt__ = __ge__ = false2
__ne__ = true2

del unop, binop, terop, false2, true2, notimpl

NaN = _NaN()

def test():
assert NaN + 1 is NaN
assert 1 & NaN is NaN
assert NaN * NaN is NaN

assert abs(NaN) is NaN
assert str(NaN)=="NaN"
assert repr(NaN)=="NaN"

assert not (NaN==NaN)
assert (NaN!=NaN)
assert not (NaN>NaN)
assert not (NaN<NaN)
assert not (NaN>=NaN)
assert not (NaN<=NaN)

assert not (NaN==1)
assert (NaN!=1)
assert not (NaN>1)
assert not (NaN<1)
assert not (NaN>=1)
assert not (NaN<=1)

assert not (1==NaN)
assert (1!=NaN)
assert not (1>NaN)
assert not (1<NaN)
assert not (1>=NaN)
assert not (1<=NaN)

assert cmp(NaN, 1)!=0
assert cmp(1, NaN)!=0
#assert cmp(NaN, NaN)!=0

assert NaN is _NaN()
assert NaN is type(NaN)()

test()



--
Gabriel Genellina

 
Reply With Quote
 
Bruno Desthuilliers
Guest
Posts: n/a
 
      09-15-2007
Zentrader a écrit :
> This would accept ints, floats, and decimal types.


It doesn't...

> import decimal


Useless

> class Nint(int):
> def __add__(self, x, y):


The prototype for __add__ is __add__(self, other)

> try:
> return x+y
> except:
> return None
>
> if __name__=='__main__':
> N=Nint()
> print N.__add__( 1, 2 )
> print N.__add__( 1, None )
> print N.__add__(decimal.Decimal("2"), decimal.Decimal("3"))
> print N.__add__(decimal.Decimal("2"), 3)
>


i = Nint(42)
i + 33
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: __add__() takes exactly 3 arguments (2 given)

The following works better (at least for integers - which is what the OP
saked for), but it's still not the solution:
import types

class Nint(int):
def __new__(cls, value=0):
# doesn't work with Nint(None)...
return int.__new__(cls, value)

def __add__(self, other):
if isinstance(other, int):
return int.__add__(self, other)
elif isinstance(other, types.NoneType):
return None
else:
err = "unsupported operand type(s) for +: '%s' and '%s'" \
% (type(self), type(other))
raise TypeError(err)



i = Nint(42)
=> 42
i + None
=> None
i + "allo"
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/usr/tmp/python-8683q3Z", line 19, in __add__
TypeError: unsupported operand type(s) for +: '<class '__main__.Nint'>'
and '<type 'str'>'

Fo some reasons I'm not sure about and didn't have time to investigate
(some guru around ?), trying to catch a TypeError in __add__ failed -
raising a TypeError ! But anyway, this isn't the correct solution since
we don't want Nint.__add__ to return None when other is neither an int
nor None.

Anyway, this still doesn't solves the OP's problem since it doesn't
satisfy isinstance(Nint(None), NoneType). I tried making Nint a subclass
of both int and NoneType, but it doesn't work for obvious reasons (None
is a singleton). The only funny thing here is the error message when
trying to call NoneType.__new__:

>>> NoneType.__new__(NoneType)

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object.__new__(NoneType) is not safe, use NoneType.__new__()
>>>


<OP>
The best I could come with is:

from types import NoneType

class Nint(int, NoneType):
def __new__(cls, value=None):
# by default, will return Nint(0) even if value is None
return int.__new__(cls, value)

def __add__(self, other):
if isinstance(other, int):
return int.__add__(self, other)
elif isinstance(other, NoneType):
return None
else:
err = "unsupported operand type(s) for +: '%s' and '%s'" \
% (type(self), type(other))
raise TypeError(err)

# other __functions__ to implement, left as an exercise to the OP

__all__ = [Nint]

Maybe some guru around will find something better, but I have some doubts...
</OP>


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Subclass of subclass Fab C++ 0 08-09-2012 09:54 AM
subclass a class in the namespace of the that subclass Trans Ruby 8 10-23-2008 07:24 AM
String subclass method returns subclass - bug or feature? S.Volkov Ruby 2 03-12-2006 06:46 PM
subclass has a variable that is subclass of same superclass jstorta Java 3 02-20-2006 08:42 PM
TreeNode subclass Booshmon ASP .Net 0 10-04-2005 08:57 PM



Advertisments