4

我正在开发一个库,该库实现了一个适用于任何有序数据类型的数据结构——一个范围集。当您允许正无穷和负无穷时,许多操作(如反转)变得有趣。

一个目标是让 datetime 对象与这个模块一起工作,并且为了支持非数字对象的无穷大,我创建了 INFINITY 和 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()

不幸的是,这不适用于在 cmp() 操作左侧的日期时间对象:

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

我曾希望我可以通过使用 cmp 包装器来解决这个限制,它只是确保我的对象总是被调用,但我真的想使用.sort()会导致在这些对象之间调用 cmp 的方法。

有没有办法创建一个真正小于任何其他对象,并且真正大于任何其他对象的对象?

模块主页:https ://github.com/axiak/py-rangeset

4

3 回答 3

5

文档

为了阻止比较回退到比较对象地址的默认方案,如果另一个比较对象不是日期对象,日期比较通常会引发 TypeError。但是,如果另一个比较具有 timetuple() 属性,则返回 NotImplemented。

所以要允许与日期时间对象进行比较,请添加一个timetuple方法,例如

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)

输出:

1    
-1
于 2011-12-08T18:32:03.010 回答
0

我不太确定,但尝试覆盖__eq____ne__(或__cmp__)以查看是否在您执行 cmp 时调用它们。您还应该知道 cmp 和__cmp__已从 python 3 中删除。

于 2011-12-08T17:45:54.050 回答
0

问题在于,这cmp(now, INFINITY)相当于datetime.__cmp__(INFINITY)直接在 datettime 类上定义。你可以通过猴子修补 dateetime 模块来解决这个问题,但这真的很hackish。

我认为你真正想要的只是一个排序函数,它考虑到你的类,并总是根据无穷大的符号把它放在前面或后面。

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
]
于 2011-12-08T18:43:36.903 回答