[英]appending a list that you are iterating over with a for loop
somebody mentioned that the function (in this case a method) below is no good as it modifies a list while iterating over it. 有人提到下面的函数(在这种情况下为方法)不好,因为它在迭代列表时会修改列表。 Why is this, as it works exactly as I intended.
为什么这样做,因为它完全符合我的预期。 I was actually quite pleased with it... Is there a better way of writing it.
实际上,我对此感到非常满意……是否有更好的书写方式。
Data structures, function and output as follows: 数据结构,功能和输出如下:
nodes = { ('foo','bar',1),
('foo','baz',1),
('baz','gad',0),
('boo','moo',1),
('goo','loo',0),
('bar','far',1),
('far','aaa',0) }
class Graph(dict):
def __missing__(self, key):
self[key] = set()
return self[key]
def add_node_pairs(self, node_pairs):
for pair in node_pairs:
nodeA, nodeB, weight = pair
self[nodeA].add((weight, nodeB))
self[nodeB].add((weight, nodeA))
def find_paths(self, keys):
paths = [(key,) for key in keys if key in self]
for path in paths:
*oldkeys, key = path
for weight, next_key in self[key]:
if next_key not in oldkeys:
paths.append( path + (weight,next_key) )
paths.sort()
return paths
graph = Graph()
graph.add_node_pairs(nodes)
print(graph)
print( graph.find_paths(['foo']))
graph: 图形:
{ 'goo': {(0, 'loo')},
'foo': {(1, 'bar'), (1, 'baz')},
'aaa': {(0, 'far')},
'far': {(1, 'bar'), (0, 'aaa')},
'baz': {(0, 'gad'), (1, 'foo')},
'loo': {(0, 'goo')},
'moo': {(1, 'boo')},
'boo': {(1, 'moo')},
'bar': {(1, 'far'), (1, 'foo')},
'gad': {(0, 'baz')} }
find_paths ('foo'): find_paths('foo'):
[ ('foo',),
('foo', 1, 'bar'),
('foo', 1, 'bar', 1, 'far'),
('foo', 1, 'bar', 1, 'far', 0, 'aaa'),
('foo', 1, 'baz'),
('foo', 1, 'baz', 0, 'gad') ]
Consider the three following examples: 考虑以下三个示例:
l = [1]
for x in l:
if x < 10 # avoid infinite loop
l.append(x+1)
print x
This code is correct and is similar to the one you are using. 此代码正确,并且与您使用的代码相似。 The output is as expected 1..10.
输出是预期的1..10。 Appending an item on a for loop is ok (or inserting an item after the current iterator position).
在for循环上添加项目是可以的(或在当前迭代器位置之后插入项目)。
Now try the same example but with an insert instead: 现在尝试使用相同的示例,但要插入一个:
l = [1]
for x in l:
if x < 10 # avoid infinite loop
l.insert(0,x+1)
print x
This time, you'll end up with a infinite loop. 这次,您将陷入无限循环。 The reason is that the for loop will always check the next item and since we are inserting x at the beginning, the checked item will always be equal to 1. Inserting an item prior to the current iterator position is usually bad.
原因是for循环将始终检查下一个项目,并且由于我们在开始处插入x,因此被检查的项目将始终等于1。在当前迭代器位置之前插入项目通常是不好的。
Finally check this example: 最后检查此示例:
l = [1,2,3,4,5]
for x in l:
print x
l.remove(x)
The output of this function will be 1,3,5 different from the expected output: 1,2,3,4,5. 此函数的输出将与预期的输出1、2、3、4、5相差1,3,5。 Therefor, removing items before the current iterator is also bad.
因此,在当前迭代器之前删除项目也是不好的。
To simplify things, let's just say that changing the content of a list while looping should be avoided, unless you know exactly what you are doing and what effects it could cause on the output. 为了简化起见,我们只能说应该避免在循环时更改列表的内容,除非您确切地知道自己在做什么以及它可能对输出造成什么影响。
Appending to a list you are iterating over is safe. 将列表附加到要迭代的列表是安全的。 If your code reviewer won't accept that, or it still feels squishy to you, you can use a two-phase approach:
如果您的代码审阅者不愿意接受,或者对您仍然感到困惑,则可以使用两阶段方法:
paths = [blah blah]
next_paths = []
while paths:
for path in paths:
if something_or_other:
next_paths.append(blah)
paths = next_paths
next_paths = []
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.