我正在使用python 2.7
考虑以下代码片段(示例是设计的):
import datetime
class ScheduleData:
def __init__(self, date):
self.date = date
def __eq__(self, other):
try:
return self.date == other.date
except AttributeError as e:
return self.date == other
def __hash__(self):
return hash(self.date)
schedule_set = set()
schedule_set.add(ScheduleData(datetime.date(2010, 8, 7)))
schedule_set.add(ScheduleData(datetime.date(2010, 8, 8)))
schedule_set.add(ScheduleData(datetime.date(2010, 8, 9)))
print (datetime.date(2010, 8, 8) in schedule_set)
schedule_list = list(schedule_set)
print (datetime.date(2010, 8, 8) in schedule_list)
这是意料之外的(至少对我来说):
[08:02 PM toolscripts]$ python test.py
True
False
在第一种情况下,由于我已覆盖schedule_set
和__hash__
函数,因此在__eq__
中找到了给定日期。
in
运算符将检查集合的哈希和相等性,但对于列表,它将简单地遍历列表中的项目并检查相等性。
那么这里发生了什么?为什么列表in
上schedule_list
的第二次测试失败?
我是否必须覆盖列表的其他一些功能?
答案 0 :(得分:9)
问题是比较是调用与你正在寻找的__eq__
函数相反的函数。如果您有__eq__
,但ScheduleData() == datetime.date()
运算符正在以相反的顺序执行比较in
,而datetime.date() == ScheduleData()
未调用您定义的__eq__
,则__eq__
方法定义有效}。只有作为左侧的班级才会调用datetime.date.__eq__
。
在python 2而不是3中出现此问题的原因与std库中class A(object):
def __eq__(self, other):
print ('A.__eq__')
return False
class B(object):
def __eq__(self, other):
print ('B.__eq__')
items = [A()]
B() in items
的定义有关。以下面两个类为例:
B.__eq__
运行此代码会在Python 2和Python 3下打印B
。datetime.date
对象用作lhs,就像在Python 2中使用B.__eq__
对象一样。但是,如果我重新定义datetime.date.__eq__
以类似于{3}的Python 3定义:
class B(object):
def __eq__(self, other):
print ('First B.__eq__')
if isinstance(self, other.__class__):
print ('B.__eq__')
return NotImplemented
然后:
First B.__eq__
A.__eq__
在Python 2和3下打印。NotImplemented
的返回导致检查反转参数。
在你的课堂上使用timetuple
将解决这个问题,正如@TimPeters所述(有趣的怪癖我不知道),虽然看起来它不一定是一个函数
class ScheduleData:
timetuple = None
除了你已经拥有的东西之外,你还需要它。
答案 1 :(得分:6)
@RyanHaining是正确的。对于一个真正奇怪的解决方法,请将此方法添加到您的类中:
def timetuple(self):
return None
然后您的程序将打印True
两次。造成这种情况的原因是,与Python 2中不幸的比较历史太过松散有关。 timetuple()
解决方法主要在文档的这一部分中进行了解释:
注意为了阻止比较从回落到 比较对象地址的默认方案,datetime 如果另一个比较,比较通常会引发TypeError 也不是日期时间对象。但是,NotImplemented是 如果另一个comparand有一个timetuple()返回 属性。这个钩子给出了其他种类的日期对象a 实施混合型比较的机会。如果不, 将datetime对象与a的对象进行比较时 除非进行比较,否则会引发TypeError 是==或!=。后一种情况返回False或True, 分别
datetime
是添加到Python的第一个类型之一,试图提供不那么令人惊讶的比较行为。但是,在Python 3之前它不会变得“非常干净”。