5

我正在尝试set().issubset()用于比较序列。正如您可以想象的那样,它没有按预期工作;)提前:对于长代码块感到抱歉。

class T(object):
  def __init__(self, value, attributes = None):
    self.value = value
    self.attributes = Attributes(attributes)

  def __eq__(self, other):
    if not isinstance(other, T):
      return False
    if self.value == other.value and self.attributes == other.attributes:
      return True
    else:
      return False

  def __ne__(self, other):
    if not isinstance(other, T):
      return True
    if self.value != other.value or self.attributes != other.attributes:
      return True
    else:
      return False

class Attributes(dict):
  def __init__(self, attributes):
    super(dict, self)
    self.update(attributes or dict())

  def __eq__(self, other):
    if self.items() == other.items():
      return True
    else:
      return False

  def __ne__(self, other):
    if not self.items() == other.items():
      return True
    else:
      return False

  def __cmp__(self, other):
    return self.items().__cmp__(other.items())


x = [T("I", {'pos': 0}), T("am", {'pos': 1}), T("a", {'pos': 2}), T("test", {'pos': 3})]
y = [T("a", {'pos': 2}), T("test", {'pos': 3})] 
xx = set(x)
yy = set(y)

assert y[0] == x[2], "__eq__ did fail, really?" #works
assert y[1] == x[3], "__eq__ did fail, really?" #works
assert xx-(yy-xx) == xx, "set subtract not working" #works, but is nonsense. see accepted answer
assert not xx.issubset(yy), "i am doing it wrong..." #works
assert yy.issubset(xx), "issubset not working :(" #FAILS!

运行上面的代码使最后一个断言失败:

$ python
Python 2.7.2 (v2.7.2:8527427914a2, Jun 11 2011, 15:22:34) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import issubsettest
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "issubsettest.py", line 52, in <module>
    assert yy.issubset(xx), "issubset not working :("
AssertionError: issubset not working :(
>>> 

我在这里想念什么?

4

1 回答 1

9

您的对象正在被他们的散列id(您没有覆盖__hash__)。当然,它们不是子集,因为它们xx包含yy独特的对象。

为了做到这一点,你需要想出某种__hash__功能。 __hash__应该始终为对象返回相同的值,这就是为什么通常认为您不会改变可散列对象的原因。例如,一种选择可能是:

class T(object):
    #<snip> ...

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

    #... </snip>

self.value具有在对象的生命周期内无法改变的理解。(注意,我并不认为这是一个好的选择。您使用的实际哈希实际上取决于您的实际应用程序


现在为什么 - 集合(和字典)背后的魔力和惊人的性能是它们依赖于哈希。基本上,每个可散列对象都会变成一个“唯一”(在完美世界中)数字。Python 将这个“唯一”数字转换为一个数组索引,它可以用来获取对象的句柄(这里的魔法有点难以解释,但对于本次讨论并不重要)。因此,与其通过将对象与“数组”(通常称为表)中的所有其他对象进行比较来查找对象 - 这是一项昂贵的操作,它还可以根据哈希值准确地知道在哪里查找对象(便宜) . 默认情况下,用户定义的对象由它们的id(内存地址)散列。创建集合xx时,python 会查看每个对象ids 并根据它们的 id 将它们放入 a 中。现在,当您这样做时xx.issubset(yy),python 会查看所有的 idxx并检查它们是否都在yy。但是它们都不在,yy因为它们都是唯一的对象(因此具有唯一的哈希值)。

但你说,“为什么xx-(yy-xx) == xx工作?” 好问题。让我们把它分开。

首先,我们有(yy - xx). 这将返回一个空集,因为同样没有元素 inxx也在其中yy(它们都散列到不同的值,因为它们都有唯一id的 s)。所以你真的在做

xx - set([]) == xx

这应该很明显为什么会这样True

于 2012-10-19T17:58:14.253 回答