简体   繁体   中英

Creating infinity and negative infinity in python for any object

I'm working on a library that implements a data structure that works with any ordered data type--a rangeset. Many of the operations (like inversion) get interesting when you allow for positive and negative infinity.

One goal is to get datetime objects to work with this module, and in supporting infinity with non-numeric objects, I've created INFINITY and NEGATIVE_INFINITY:

class _Indeterminate(object):
    def __eq__(self, other):
        return other is self

@functools.total_ordering
class _Infinity(_Indeterminate):
    def __lt__(self, other):
        return False
    def __gt__(self, other):
        return True
    def __str__(self):
        return 'inf'
    __repr__ = __str__

@functools.total_ordering
class _NegativeInfinity(_Indeterminate):
    def __lt__(self, other):
        return True
    def __gt__(self, other):
        return False
    def __str__(self):
        return '-inf'

INFINITY = _Infinity()
NEGATIVE_INFINITY = _NegativeInfinity()

Unfortunately, this doesn't work for datetime objects when on the left hand side of the cmp() operation:

In [1]: from rangeset import *
In [2]: from datetime import datetime
In [3]: now = datetime.now()
In [4]: cmp(INFINITY, now)
Out[4]: 1
In [5]: cmp(now, INFINITY)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/home/axiak/Documents/rangeset/<ipython-input-5-c928d3687d92> in <module>()
----> 1 cmp(now, INFINITY)

TypeError: can't compare datetime.datetime to _Infinity

I had hoped I could get around this limitation by using a cmp wrapper that just ensures that my objects are always called, but I really want to use the .sort() method which will cause cmp to be called between these objects.

Is there any way to create an object which is truly less than any other object, and truly greater than any other object?

Module home: https://github.com/axiak/py-rangeset

from the docs

In order to stop comparison from falling back to the default scheme of comparing object addresses, date comparison normally raises TypeError if the other comparand isn't also a date object. However, NotImplemented is returned instead if the other comparand has a timetuple() attribute.

so to allow comparison with datetime objects add a timetuple method eg

class _Infinity(object):

    def __lt__(self, other):
        return False

    def __gt__(self, other):
        return True

    def timetuple(self):
        return tuple()

import datetime
INF = _Infinity()
now = datetime.datetime.now()
print cmp(INF, now)
print cmp(now, INF)

output:

1    
-1

I'm not really sure but try to overwrite __eq__ and __ne__ (or __cmp__ ) to see if they are called whenever you do cmp. You also should be aware that cmp and __cmp__ is removed from python 3.

Problem is that cmp(now, INFINITY) is equivalent to datetime.__cmp__(INFINITY) which is defined directly on the datettime class. You could get around this by monkey-patching the dateetime module but thats really hackish.

I think what you really want is just a sort function which takes into account your class and always puts it in front or back depending on the sign of the infinity.

def order(x, y):
    if isinstance(x,_Infinity):
        return -1
    if isinstance(y, _Infinity):
        return 1
    elif isinstance(x, _NegativeInfinity):
        return 1
    elif isinstance(y, _NegativeInfinity):
         return -1
    else:
        return cmp(x,y)

>>> sorted([datetime.datetime.now(), datetime.datetime.now(), INFINITY, NEGATIVE_INFINITY], cmp=order)
[ 
    NEGATIVE_INFINITY, 
    datetime.datetime(2011, 12, 8, 13, 38, 47, 428626),
    datetime.datetime(2011, 12, 8, 13, 38, 47, 428661),
    INFINITY
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM