Dav*_*hel 0 python iteration set python-2.7
我有一个循环的形式for thing in a_set:
.它工作不正确,因为偶尔和不一致,它会从集合中拉两次相同的东西.(这不会导致程序崩溃.它只是得到了错误的答案.)我无法确定任何对错误行为具有确定性的东西; 但是我调试它的尝试很明显,有时会发生奇怪的事情.在我最密切观察的情况下,集合中有3个项目(之前和之后),循环执行4次,一次重复其中一个项目.这些项是对我创建的类的对象的引用(更像是一个C结构).当我将for语句更改为时,不良行为消失了for thing in list(a_set):
.
我完全不知道解释错误的行为.我非常肯定循环体中没有任何东西可以导致它发生的事情发生两次或改变事物变量的值.我相当肯定循环中发生的事情不会试图影响集合的组成.此外,即使它可以,我相信这会导致RuntimeError
.我对提出可能造成这种情况的假设提出了完全的损失.缺乏连续运行相同代码的可重复性尤其神秘.我尝试在更简单的场景中重新创建症状失败了.尽管如此,我仍然觉得将list()
调用留在那里只是为了解决一个我无法解释的问题.任何其他人的假设都会受到欢迎.我需要有关在调试时应该尝试消除哪些事情的想法.
更新:我认为这个问题被错误地搁置了,因为声称它不在主题上.在这种情况下,缺乏可重复性是一个问题,我怀疑我缺少这种语言的一些细微差别.事实上,这不变成这样的情况,和MSeifert的回答让我来说明是什么导致了它.然而,正如我在回答他的评论中所指出的那样,这并不像他推测的那么简单.
我还混淆了这个问题,说集合中的对象是可变的.他们不是.它们是对属性可更改的对象的引用.(这可以从我写的内容中推断出来,但是我在一般意义上错误地使用了"mutable"这个词而不是Python的技术含义.)散列的是对象的地址,与其值无关.属性.如果这些对象引用是可变的,那么Python绝不会让我把它们放在一个集合中.
如果在添加时错误消失,list(a_set)
则很可能在迭代期间更改了设置.一般RuntimeError
情况下会抛出一个但是如果你添加了多少元素,你就不会触发它:
a = {1,2,3}
for item in a:
print(item)
a.add(item+3) # add one item
a.remove(item) # remove one item
Run Code Online (Sandbox Code Playgroud)
将数字打印1
到31
(数量实际上是一个实现细节,因此您可能会看到不同的数量)以及循环之前和之后以及每次迭代开始时set
包含3
元素.
但是,如果我添加一个list
调用,它会创建原始集的副本(作为列表),并且只迭代原始集中存在的元素:
a = {1,2,3}
for item in list(a):
print(item)
a.add(item+3)
a.remove(item)
print(a)
Run Code Online (Sandbox Code Playgroud)
打印:
1
2
3
set([4, 5, 6]) # totally changed!
Run Code Online (Sandbox Code Playgroud)
在注释中你注意到你在集合中的类是可变的,所以即使你可能认为你删除并添加相同的元素,它可能不再是相同的元素(从视角来看set
).一般情况下,你不应该将可变类放入a set
或作为键中的键,dict
因为你必须非常小心,可变性不会影响__hash__
或__eq__
方法的结果.
只是一个迭代一个看似"随机"数量的集合元素的例子:
class Fun(object):
def __init__(self, value):
self.value = value
def __repr__(self):
return '{self.__class__.__name__}({self.value})'.format(self=self)
def __eq__(self, other):
return self.value == other.value
a = {Fun(1),Fun(2),Fun(3)}
for item in a:
print(item)
a.add(Fun(item.value+3))
a.remove(item)
Run Code Online (Sandbox Code Playgroud)
实际上会显示一个"随机"(不是真正随机的,它只取决于实例的哈希值,在这种情况下,哈希值取决于id
每次运行代码时更改的类对象)每次运行时Fun
对象的数量片段.
归档时间: |
|
查看次数: |
113 次 |
最近记录: |