python集合包含vs.列表包含

2024-10-01 07:12:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用的是python2.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)

结果是出乎意料的(至少对我来说):

^{pr2}$

在第一种情况下,给定的日期在schedule_set中找到,因为我已经覆盖了__hash__和{}函数。在

根据我的理解,in运算符将检查集合的哈希和相等性,但对于列表,它将简单地迭代列表中的项并检查相等性。在

那么这里发生了什么?为什么我对列表in的第二个测试失败?在

是否必须重写其他列表函数?在


Tags: inselfadd列表datetimedatereturndef
2条回答

@ryanhaing是对的。对于真正奇怪的解决方法,请将此方法添加到类中:

def timetuple(self):
    return None

然后程序将打印True两次。这其中的原因是,与Python2中比较过于松散的不幸历史有关。timetuple()解决方法主要在文档的这一部分中解释:

Note In order to stop comparison from falling back to the default scheme of comparing object addresses, datetime comparison normally raises TypeError if the other comparand isn’t also a datetime object. However, NotImplemented is returned instead if the other comparand has a timetuple() attribute. This hook gives other kinds of date objects a chance at implementing mixed-type comparison. If not, when a datetime object is compared to an object of a different type, TypeError is raised unless the comparison is == or !=. The latter cases return False or True, respectively.

datetime是最早添加到Python中的类型之一,它试图提供不那么令人惊讶的比较行为。但是,直到Python3,它才变得“真正干净”。在

问题是,比较调用的是与您所寻找的相反的__eq__函数。当您有一个ScheduleData() == datetime.date()in运算符以相反的顺序执行比较,datetime.date() == ScheduleData()而不是调用您定义的__eq__,定义的__eq__就可以工作了。只有充当左侧的类才会调用其__eq__。在

这个问题出现在python2而不是3中的原因与std库中datetime.date.__eq__的定义有关。以以下两类为例:

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

运行此代码将在Python2和Python3下打印B.__eq__B对象用作lhs,就像您的datetime.date对象在python2中使用一样。但是,如果我重新定义B.__eq__以类似于python3对datetime.date.__eq__的定义:

^{pr2}$

然后:

First B.__eq__
A.__eq__ 

在Python 2和Python 3下打印。返回NotImplemented会导致参数颠倒的检查。在

在你的类中使用timetuple可以解决这个问题,正如@TimPeters所说(有趣的怪癖我不知道),尽管它似乎不需要是一个函数

class ScheduleData:
    timetuple = None

是你所需要的,除了你已经拥有的。在

相关问题 更多 >