Python 比较运算符重载

3 投票
3 回答
6058 浏览
提问于 2025-04-17 15:19

在我的Python 2.7.3项目中,有一个叫做 custom_date 的类,它里面有一个属性叫 fixed_date

from datetime import date
class custom_date():
    def __init__(self, fixed_date):
        self.fixed_date = fixed_date

    def __lt__(self, other):
        return self.fixed_date < other

    #__gt__, __ge__, __le__, __eq__, __ne__ all implemented the same way

我的想法是能够直接把 custom_date.fixed_date 和内置的 date 进行比较。

问题

如果我把一个 custom_date 对象和一个 date 对象进行比较,那是没问题的。但是,如果我把一个 date 对象和一个 custom_date 对象进行比较,就会出现 TypeError 的错误。

>>> from datetime import date
>>> x = custom_date(date(2013,2,1))
>>> y = date(2013,2,2)
>>> x > y
False
>>> y > x
TypeError: can't compare datetime.date to instance 

有没有什么办法可以解决这个问题呢?

3 个回答

2

找到一个可能的解决办法,供其他遇到同样问题的人参考。

来自Python的日期时间文档

换句话说,date1 小于 date2 只有在 date1.toordinal() 小于 date2.toordinal() 的情况下才成立。为了避免比较回退到默认的对象地址比较,通常如果另一个比较对象不是日期对象,日期比较会抛出类型错误(TypeError)。但是,如果另一个比较对象有 timetuple() 属性,则会返回 NotImplemented。这给其他类型的日期对象提供了实现混合类型比较的机会。如果没有,当一个日期对象与不同类型的对象比较时,除非比较是 == 或 !=,否则会抛出类型错误。后者的情况会分别返回 False 或 True。

如果 x.__op__(y) 返回 NotImplemented 而不是抛出 TypeError,Python 会自动尝试反向比较 y.__rop__(x)(关于比较的更多信息可以点击这里)。

然而,如果另一个对象不是 date 对象,date 会抛出 TypeError除非另一个对象实现了 timetuple() 属性

所以解决办法就是在我的类中添加一个虚拟的 timetuple() 方法。

from datetime import date
class custom_date():
    def __init__(self, fixed_date):
        self.fixed_date = fixed_date

    def __lt__(self, other):
        return self.fixed_date < other

    #__gt__, __ge__, __le__, __eq__, __ne__ all implemented the same way

    def timetuple():
        pass
4

我想我知道你遇到问题的原因。可以去看看 Python的数据模型文档

>>> y > x

调用:

y.__gt__(x)

x只是一个实例对象,而不是存储在其中的fixed_date属性:

>>> x
<__main__.custom_date instance at 0x020D78C8>
>>> x.fixed_date
datetime.date(2012, 2, 1)

让它按你设置的方式工作的一个方法是:

>>> y > x.fixed_date

我觉得要“修复”这个问题,你需要把所有的日期都设为custom_date类型。也许其他人会给你更好的解决方案,我会继续关注,因为我也很好奇。

3

只需创建一个 date 的子类,就能实现这个功能。因为 datetime 对象是不可变的,所以你需要使用 __new__ 构造函数,而不是 __init__

from datetime import date
class custom_date(date):
    def __new__(cls, year,month,day):
        return date.__new__(cls, year, month,day)

x = custom_date(2013,2,1)
y = date(2013,2,2)

print x<y
print y<x

输出结果:

True
False

在比较时,决定性类是 LH 类,所以左边的类需要有正确的比较运算符,以便能和右边的类进行比较。如果两个类都没有比较运算符,那么实例会根据它们的身份进行排序,也就是它们的内存地址。你的错误本质上是试图把一个苹果和一个橙子进行比较:身份和日期类之间的比较。

需要注意的是,之前在 Python 2.1 中有一个 rcmp 的功能,用来处理这类问题,但它已经被移除了。新样式类的引入和 丰富比较 的概念也导致了 __cmp__ 被弃用。

撰写回答