我正在尝试使用set().issubset()
来比较序列。你可以想象,它没有像预期的那样工作;)提前:抱歉长代码blob。
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 :(
>>>
我在这里缺少什么?
答案 0 :(得分:9)
您的id
(您没有覆盖__hash__
)正在对您的对象进行哈希处理。当然,它们不是子集,因为xx
和yy
包含唯一对象。
为了做到这一点,你需要提出某种__hash__
功能。 __hash__
应始终为对象返回相同的值,这就是为什么通常会理解您不会改变可哈希对象的原因。例如,一个选择可能是:
class T(object):
#<snip> ...
def __hash__(self):
return hash(self.value)
#... </snip>
了解到self.value
无法在对象的生命周期中发生变化。 (注意,我并不认为这是一个不错的选择。您使用的实际哈希实际上取决于您的实际应用)
现在为什么 - 设置(和dicts)背后的魔力和惊人的表现是他们依赖哈希。基本上,每个可清洗的对象都会变成一个“独特的”(在一个完美的世界中)数字。 Python接受“唯一”数字并将其转换为可用于获取对象句柄的数组索引(这里的魔术有点难以解释,但对于此讨论并不重要)。因此,不是通过将对象与“数组”中的所有其他对象(通常称为表)进行比较来寻找对象 - 这是一项昂贵的操作,而是根据哈希值(便宜)确切知道在哪里查找对象。默认情况下,用户定义的对象按其id
(内存地址)进行哈希处理。当你创建集合xx
时,python会查看每个对象id
并根据它们的ID将它们放入。现在当你执行xx.issubset(yy)
时,python会查看xx
中的所有ID,并检查它们是否全部在yy
中。但是它们都不在yy
中,因为它们都是唯一的对象(因此具有唯一的哈希值)。
但你说,“为什么xx-(yy-xx) == xx
有效?”好问题。让我们分开。
首先,我们有(yy - xx)
。这将返回空集,因为xx
中的任何元素都不在yy
中(它们都散列为不同的值,因为它们都具有唯一的id
s) 。所以你真的在做
xx - set([]) == xx
这应该是非常明显的原因True
。