【问题标题】:Python 2: different meaning of the 'in' keyword for sets and listsPython 2:集合和列表的“in”关键字的不同含义
【发布时间】:2012-02-13 04:02:35
【问题描述】:

考虑这个sn-p:

class SomeClass(object):

    def __init__(self, someattribute="somevalue"):
        self.someattribute = someattribute

    def __eq__(self, other):
        return self.someattribute == other.someattribute

    def __ne__(self, other):
        return not self.__eq__(other)

list_of_objects = [SomeClass()]
print(SomeClass() in list_of_objects)

set_of_objects = set([SomeClass()])
print(SomeClass() in set_of_objects)

计算结果为:

True
False

谁能解释为什么'in'关键字对集合和列表有不同的含义? 我本来希望两者都返回 True,尤其是在被测试的类型定义了相等方法时。

【问题讨论】:

  • 请参阅stackoverflow.com/questions/7549709/… .. 顺便说一句,在 Python 3 中运行此代码会提示正在发生的事情:“TypeError: unhashable type: 'SomeClass'”
  • 谢谢大家,现在一切都清楚了。
  • 顺便说一句,您知道您的someattributeclass 属性而不是 instance 属性,对吧?你听说过__init__,对吧?
  • @Karl:是的,为现实主义而编辑

标签: python list set equality


【解决方案1】:

含义相同,但实现方式不同。列表只是检查每个对象,检查是否相等,因此它适用于您的类。设置首先散列对象,如果它们没有正确实现散列,则设置似乎不起作用。

您的类定义了__eq__,但没有定义__hash__,因此不能正常用于集合或字典的键。 __eq____hash__ 的规则是 __eq__ 为 True 的两个对象也必须具有相等的哈希值。默认情况下,对象根据其内存地址进行哈希处理。因此,根据您的定义,您的两个相等的对象不提供相同的哈希,因此它们违反了关于 __eq____hash__ 的规则。

如果您提供__hash__ 实现,它将正常工作。对于您的示例代码,它可能是:

def __hash__(self):
    return hash(self.someattribute)

【讨论】:

  • 这是 Python 3 更清楚地处理的事情之一:它将拒绝从任何没有 __hash__() 的对象中创建一个集合。 Python 2 有一个默认的__hash__(),它反映了对象的身份而不是平等。
  • 实际上,发生的事情是经典类的行为方式相同(如果您确实定义了 __cmp__ 和/或 __eq__,则不定义 __hash__ 方法会给您一个引发 TypeError 的默认值,) 但后来引入了新样式的类(在 Python 2.2 中)并且没有正确复制该行为。足够多的版本错过了这种疏忽,以至于更改它可能会破坏太多代码,因此修复它被推迟到 Python 3。
【解决方案2】:

在几乎所有的哈希表实现中,包括 Python 的,如果你重写相等方法,你必须重写哈希方法(在 Python 中,这是__hash__)。列表的 in 运算符仅检查列表中每个元素的相等性,用于设置的 in 运算符首先对您要查找的对象进行散列,检查散列表的该槽中的对象,然后检查是否相等如果插槽中有任何东西。因此,如果您在不覆盖 __hash__ 的情况下覆盖 __eq__,则无法保证集合的 in 运算符将检查正确的插槽。

【讨论】:

    【解决方案3】:

    定义与您的__eq__() 方法对应的__hash__() 方法。 Example.

    【讨论】:

      猜你喜欢
      • 2015-08-03
      • 1970-01-01
      • 2019-06-20
      • 2021-11-18
      • 1970-01-01
      • 1970-01-01
      • 2011-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多