重新插入set元素会创建孔

时间:2015-12-12 11:23:45

标签: python set

通常,如果我们需要将一个对象插入到一个集合中,我们应该使它可以散列(通过实现散列函数)和可比较的(并实现一个比较函数)。 Set不提供访问其元素的机制,因此不能直接变异,但很容易被规避。 改变设定项目的一般模式如下

i = next(iter(x))
update(i)
x.add(i)

这通常似乎适用于几乎所有情况,除非是在创建意外漏洞时。

class Foo(object):
    def __init__(self, x):
        self.x = x
        self.count = 0
    def __hash__(self):
        return hash((self.x, ))
    def __iadd__(self, n):
        self.count += n
    def __eq__(self, other):
        return self.x == other.x


>>> x = {Foo(1)}
>>> i = next(iter(x))
>>> i+=1
>>> x.add(i)
>>> x
set([None, <__main__.Foo object at 0x0279D8B0>])

我的猜测是改变一个set元素,而更新可能会导致意外行为,但是调用next只会获取不应该成为问题的值(我猜的副本)。

知道问题可能是什么?

2 个答案:

答案 0 :(得分:3)

Per the docs

  

[__iadd__]应该尝试就地进行操作(修改自我)和     返回结果(可能是,但不一定是自己)

因此,

def __iadd__(self, n):
    self.count += n
    return self

然后,

class Foo(object):
    def __init__(self, x):
        self.x = x
        self.count = 0
    def __hash__(self):
        return hash((self.x, ))
    def __iadd__(self, n):
        self.count += n
        return self
    def __eq__(self, other):
        return self.x == other.x

x = {Foo(1)}
i = next(iter(x))
i+=1
x.add(i)
print(x)

产量

set([<__main__.Foo object at 0x7f19ae8b9f10>])

答案 1 :(得分:1)

您可能希望以 iadd 方式返回自我。