当迭代器在嵌套的 while 循环中被覆盖时,`for i in range()` 会发生什么?
What happens to `for i in range()` when iterator is overwritten in nested while loop?
当迭代器在嵌套的 while 循环中被覆盖时 for i in range()
会发生什么?例如,为什么以下代码片段会给出不同的输出?当我在 while 循环中更改变量 i
和 j
的名称时,代码片段的行为与我预期的一样。但是,当 while 循环覆盖 i
和 j
时,for
循环会受到影响。 for
循环的迭代器在 while
中被覆盖时的结果行为是否可预测?
(一)
for i in range (0,3):
for j in range (0,3):
print "after nested for i,j",i,j
counter = 0
while counter < 3:
counter += 1
i = counter
j = counter
有o/p:
after nested for i,j 0 0
after nested for i,j 3 1
after nested for i,j 3 2
after nested for i,j 1 0
after nested for i,j 3 1
after nested for i,j 3 2
after nested for i,j 2 0
after nested for i,j 3 1
after nested for i,j 3 2
(b)(与 while
注释相同的代码)
for i in range (0,3):
for j in range (0,3):
print "after nested for i,j",i,j
有o/p
after nested for i,j 0 0
after nested for i,j 0 1
after nested for i,j 0 2
after nested for i,j 1 0
after nested for i,j 1 1
after nested for i,j 1 2
after nested for i,j 2 0
after nested for i,j 2 1
after nested for i,j 2 2
如果我很清楚你的问题,那么这里是解决方案:
函数中定义的变量具有函数作用域,并且只在函数体中可见。
您可以在不同的功能中使用相同的名称。
代码 1:
def VAR1():
var = 'foo'
def inner():
var = 'bar'
print 'inside function, var is ', var
inner()
print 'outside function, var is ', var
VAR1()
输出:
inside function, var is bar
outside function, var is foo
但是在单个函数中,变量是局部的。你不能在不同的地方使用相同的名字
代码 1:
def VAR():
var = 'foo'
if True:
var = 'bar'
print 'inside if, var is ', var
print 'outside if, var is ', var
VAR()
输出:
inside if, var is bar
outside if, var is bar
您的术语有点错误。在 for 循环中,您无权访问迭代器。迭代器隐藏在幕后。以下循环结构是等价的。
for i in range(10):
print(i)
it = iter(range(10)):
while True:
try:
i = next(it)
except StopIteration:
break
print(i)
如您所见,迭代器对象 (it
) 隐藏在 for 循环中。可以在 for 循环中公开迭代器,但这是一个不同的问题。
您所说的是存储可迭代元素的名称。如果您在循环过程中重写该名称,那么在下一次迭代开始时该值将被忽略的循环。这在循环结构的 while 版本中很容易看出,其中所做的第一件事是将名称 i
分配给 iterator.whil
返回的下一个元素
我不确定您的代码的用途,但可以更改您正在使用的迭代器的状态。为此,您必须写一个 coroutine。协程是一种能够接受输入的专用生成器。
def generator_range(start, end, step=1):
"Simplified version of the range/xrange function written as a generator."
counter = start
while counter < end:
yield counter
counter += step
def coroutine_range(start, end, step=1):
"Special version of range that allows the internal counter to set."
counter = start
while counter < end:
sent = yield counter
if sent is None:
counter += step
else:
counter = sent
对于简单范围的使用,生成器版本的行为相同。
例如
assert list(range(0, 10)) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
assert list(range(0, 10)) == list(generator_range(0, 10))
assert list(range(0, 10)) == list(coroutine_range(0, 10))
但是我们可以用协程做更复杂的循环算法。
例如
# skip numbers in range 3-7 inclusive
l = []
co = coroutine_range(0, 10)
item_to_send = None
while True:
try:
i = co.send(item_to_send)
# if item_to_send is None then the above is the same as next(co)
item_to_send = None
except StopIteration:
break
if 3 <= i <= 7:
item_to_send = 8
else:
l.append(i)
assert l == [0, 1, 2, 8, 9]
我认为这确实是一个变量范围的问题。 i
和 j
在局部函数命名空间中。 while 循环不创建新的命名空间,所以在代码片段
while len(list) < 2:
i = i
j = j
i
和 'j' 仍然是本地命名空间中的相同变量,您所做的只是将它们重新分配给自己。您没有创建新的 i
或 j
。它无害,但应删除这些分配。
稍后,在 while
循环的底部,当您执行
i = PixelCoord[Lightest[1]][0]
j = PixelCoord[Lightest[1]][1]
您将保存 for
循环中的迭代值的局部函数命名空间中的 i
和 j
重新分配给其他对象。 j
相对良性,因为您 return 到内部 for
循环并且 j
被重新分配到下一个迭代值。但这对 x
来说是个问题,因为它将保持更改的值,直到再次到达外部 for
。
你可以通过几个打印语句清楚地看到问题
for i in range (1,array.shape[0]-1):
print('outer for, i is', i)
for j in range (1,array.shape[1]-1):
print('inner for, i and j are', i, j)
解决方法是使用不同的变量名。
这说明了您的 case(a)
:
中发生了什么
for i in range(0,2):
for j in range(0,2):
print(i,j)
i = 'new-i'
j = 'new-j'
print(' ', i,j)
输出:
0 0 # i and j set by the for statements
new-i new-j # i and j set by the inner assignments
new-i 1 # new j set by its for; i unchanged
new-i new-j
1 0 # new i and j set by for
new-i new-j
new-i 1
new-i new-j
i
和 j
变量没有什么特别之处,只是它们在各自的循环开始时获得新值。在循环之后,i
和 j
将在循环中具有它们的最后一个值,在本例中为 new-i
和 new-j
.
对于像这样的简单循环,您可以 fiddle 随心所欲地使用 i
的值,并且不会弄乱迭代(即 for
语句)。但是因为它会让你和你的算法(以及你的读者)感到困惑,重新分配 for
迭代变量通常不是一个好主意。
要将迭代变量与 while
循环中的更改完全分开,您需要定义一个函数,如下所示:
def foo(i,j):
print("after nested for i,j",i,j)
counter = 0
while counter < 3
counter += 1
i = counter
j = counter
for i in range(3):
for j in range(3):
foo(i,j)
生产:
after nested for i,j 0 0
after nested for i,j 0 1
...
after nested for i,j 2 1
after nested for i,j 2 2
另一方面,如果您希望更改内部 while
来控制 i
的迭代,您还需要在外部循环中使用 while
:
i = 0
while i<3:
j = 0
while j<3:
print("after nested for i,j",i,j)
counter = 0
while counter < 3:
counter += 1
i = counter
j = counter
只打印一次(i
和 j
都跳到 3)
当迭代器在嵌套的 while 循环中被覆盖时 for i in range()
会发生什么?例如,为什么以下代码片段会给出不同的输出?当我在 while 循环中更改变量 i
和 j
的名称时,代码片段的行为与我预期的一样。但是,当 while 循环覆盖 i
和 j
时,for
循环会受到影响。 for
循环的迭代器在 while
中被覆盖时的结果行为是否可预测?
(一)
for i in range (0,3):
for j in range (0,3):
print "after nested for i,j",i,j
counter = 0
while counter < 3:
counter += 1
i = counter
j = counter
有o/p:
after nested for i,j 0 0
after nested for i,j 3 1
after nested for i,j 3 2
after nested for i,j 1 0
after nested for i,j 3 1
after nested for i,j 3 2
after nested for i,j 2 0
after nested for i,j 3 1
after nested for i,j 3 2
(b)(与 while
注释相同的代码)
for i in range (0,3):
for j in range (0,3):
print "after nested for i,j",i,j
有o/p
after nested for i,j 0 0
after nested for i,j 0 1
after nested for i,j 0 2
after nested for i,j 1 0
after nested for i,j 1 1
after nested for i,j 1 2
after nested for i,j 2 0
after nested for i,j 2 1
after nested for i,j 2 2
如果我很清楚你的问题,那么这里是解决方案:
函数中定义的变量具有函数作用域,并且只在函数体中可见。 您可以在不同的功能中使用相同的名称。
代码 1:
def VAR1():
var = 'foo'
def inner():
var = 'bar'
print 'inside function, var is ', var
inner()
print 'outside function, var is ', var
VAR1()
输出:
inside function, var is bar
outside function, var is foo
但是在单个函数中,变量是局部的。你不能在不同的地方使用相同的名字
代码 1:
def VAR():
var = 'foo'
if True:
var = 'bar'
print 'inside if, var is ', var
print 'outside if, var is ', var
VAR()
输出:
inside if, var is bar
outside if, var is bar
您的术语有点错误。在 for 循环中,您无权访问迭代器。迭代器隐藏在幕后。以下循环结构是等价的。
for i in range(10):
print(i)
it = iter(range(10)):
while True:
try:
i = next(it)
except StopIteration:
break
print(i)
如您所见,迭代器对象 (it
) 隐藏在 for 循环中。可以在 for 循环中公开迭代器,但这是一个不同的问题。
您所说的是存储可迭代元素的名称。如果您在循环过程中重写该名称,那么在下一次迭代开始时该值将被忽略的循环。这在循环结构的 while 版本中很容易看出,其中所做的第一件事是将名称 i
分配给 iterator.whil
我不确定您的代码的用途,但可以更改您正在使用的迭代器的状态。为此,您必须写一个 coroutine。协程是一种能够接受输入的专用生成器。
def generator_range(start, end, step=1):
"Simplified version of the range/xrange function written as a generator."
counter = start
while counter < end:
yield counter
counter += step
def coroutine_range(start, end, step=1):
"Special version of range that allows the internal counter to set."
counter = start
while counter < end:
sent = yield counter
if sent is None:
counter += step
else:
counter = sent
对于简单范围的使用,生成器版本的行为相同。
例如
assert list(range(0, 10)) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
assert list(range(0, 10)) == list(generator_range(0, 10))
assert list(range(0, 10)) == list(coroutine_range(0, 10))
但是我们可以用协程做更复杂的循环算法。
例如
# skip numbers in range 3-7 inclusive
l = []
co = coroutine_range(0, 10)
item_to_send = None
while True:
try:
i = co.send(item_to_send)
# if item_to_send is None then the above is the same as next(co)
item_to_send = None
except StopIteration:
break
if 3 <= i <= 7:
item_to_send = 8
else:
l.append(i)
assert l == [0, 1, 2, 8, 9]
我认为这确实是一个变量范围的问题。 i
和 j
在局部函数命名空间中。 while 循环不创建新的命名空间,所以在代码片段
while len(list) < 2:
i = i
j = j
i
和 'j' 仍然是本地命名空间中的相同变量,您所做的只是将它们重新分配给自己。您没有创建新的 i
或 j
。它无害,但应删除这些分配。
稍后,在 while
循环的底部,当您执行
i = PixelCoord[Lightest[1]][0]
j = PixelCoord[Lightest[1]][1]
您将保存 for
循环中的迭代值的局部函数命名空间中的 i
和 j
重新分配给其他对象。 j
相对良性,因为您 return 到内部 for
循环并且 j
被重新分配到下一个迭代值。但这对 x
来说是个问题,因为它将保持更改的值,直到再次到达外部 for
。
你可以通过几个打印语句清楚地看到问题
for i in range (1,array.shape[0]-1):
print('outer for, i is', i)
for j in range (1,array.shape[1]-1):
print('inner for, i and j are', i, j)
解决方法是使用不同的变量名。
这说明了您的 case(a)
:
for i in range(0,2):
for j in range(0,2):
print(i,j)
i = 'new-i'
j = 'new-j'
print(' ', i,j)
输出:
0 0 # i and j set by the for statements
new-i new-j # i and j set by the inner assignments
new-i 1 # new j set by its for; i unchanged
new-i new-j
1 0 # new i and j set by for
new-i new-j
new-i 1
new-i new-j
i
和 j
变量没有什么特别之处,只是它们在各自的循环开始时获得新值。在循环之后,i
和 j
将在循环中具有它们的最后一个值,在本例中为 new-i
和 new-j
.
对于像这样的简单循环,您可以 fiddle 随心所欲地使用 i
的值,并且不会弄乱迭代(即 for
语句)。但是因为它会让你和你的算法(以及你的读者)感到困惑,重新分配 for
迭代变量通常不是一个好主意。
要将迭代变量与 while
循环中的更改完全分开,您需要定义一个函数,如下所示:
def foo(i,j):
print("after nested for i,j",i,j)
counter = 0
while counter < 3
counter += 1
i = counter
j = counter
for i in range(3):
for j in range(3):
foo(i,j)
生产:
after nested for i,j 0 0
after nested for i,j 0 1
...
after nested for i,j 2 1
after nested for i,j 2 2
另一方面,如果您希望更改内部 while
来控制 i
的迭代,您还需要在外部循环中使用 while
:
i = 0
while i<3:
j = 0
while j<3:
print("after nested for i,j",i,j)
counter = 0
while counter < 3:
counter += 1
i = counter
j = counter
只打印一次(i
和 j
都跳到 3)