subclass of integers

Discussion in 'Python' started by Mark Morss, Sep 14, 2007.

  1. Mark Morss

    Mark Morss Guest

    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.
     
    Mark Morss, Sep 14, 2007
    #1
    1. Advertising

  2. Mark Morss

    Mark Morss Guest

    On Sep 14, 10:30 am, 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.


    I meant of course that arithmetic operations between integer elements
    would return the same result as the corresponding integer operations,
    not necessarily addition.
     
    Mark Morss, Sep 14, 2007
    #2
    1. Advertising

  3. Mark Morss

    Zentrader Guest

    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 )
     
    Zentrader, Sep 14, 2007
    #3
  4. Mark Morss

    Zentrader Guest

    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)
     
    Zentrader, Sep 14, 2007
    #4
  5. 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/releases/2.2.3/descrintro/
    But unless there's more to your requirement than you set out above, it's
    probably not worth the trouble.

    HTH, Michael
     
    Michael Spencer, Sep 14, 2007
    #5
  6. Mark Morss

    Ian Clark Guest

    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
     
    Ian Clark, Sep 14, 2007
    #6
  7. Mark Morss

    Ian Clark Guest

    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
     
    Ian Clark, Sep 14, 2007
    #7
  8. Mark Morss

    Dan Bishop Guest

    On Sep 14, 9:30 am, 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.


    Rather than subclassing int, why not just make a singleton NaN object
    with overloaded arithmetic operators that all return NaN?
     
    Dan Bishop, Sep 15, 2007
    #8
  9. En Fri, 14 Sep 2007 20:16:36 -0300, Dan Bishop <>
    escribi�:

    > On Sep 14, 9:30 am, 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.

    >
    > 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
     
    Gabriel Genellina, Sep 15, 2007
    #9
  10. 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>
     
    Bruno Desthuilliers, Sep 15, 2007
    #10
  11. Mark Morss a écrit :
    > 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.


    You'll find documentation in the FineManual(tm):
    http://docs.python.org/ref/customization.html
    http://www.python.org/download/releases/2.2.3/descrintro/#__new__

    and a possible (even if imperfect IMHO) example in my answer to
    Zentrader in the thread.

    Now would you be kind enough to satisfy my curiousity and explain your
    use case ?-)
     
    Bruno Desthuilliers, Sep 15, 2007
    #11
  12. On Sep 14, 10:30 am, 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.


    No need to create a new class:

    try:
    result = a * b
    except TypeError:
    result = None

    --
    Roberto Bonvallet
     
    Roberto Bonvallet, Sep 16, 2007
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Booshmon

    TreeNode subclass

    Booshmon, Oct 4, 2005, in forum: ASP .Net
    Replies:
    0
    Views:
    539
    Booshmon
    Oct 4, 2005
  2. jstorta
    Replies:
    3
    Views:
    457
    jstorta
    Feb 20, 2006
  3. S.Volkov
    Replies:
    2
    Views:
    232
    S.Volkov
    Mar 12, 2006
  4. Trans
    Replies:
    8
    Views:
    333
    Robert Klemme
    Oct 23, 2008
  5. Fab

    Subclass of subclass

    Fab, Aug 9, 2012, in forum: C++
    Replies:
    0
    Views:
    404
Loading...

Share This Page