python set contains包含列表

时间:2013-11-26 04:04:00

标签: python list set contains equality

我正在使用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运算符将检查集合的哈希和相等性,但对于列表,它将简单地遍历列表中的项目并检查相等性。

那么这里发生了什么?为什么列表inschedule_list的第二次测试失败?

我是否必须覆盖列表的其他一些功能?

2 个答案:

答案 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下打印Bdatetime.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之前它不会变得“非常干净”。