这是一个有效的python行为吗?我认为最终结果应该是[0,0,0]并且id()函数应该在每次迭代时返回相同的值。如何使它成为pythonic,而不是使用枚举或范围(len(bar))?
bar = [1,2,3]
print bar
for foo in bar:
print id (foo)
foo=0
print id(foo)
print bar
输出:
[1, 2, 3]
5169664
5169676
5169652
5169676
5169640
5169676
[1, 2, 3]
答案 0 :(得分:21)
首先,你不能重新分配循环变量,你可以,但这不会改变你正在迭代的列表。因此设置foo = 0
不会更改列表,只会更改局部变量foo
(恰好包含每次迭代开始时迭代的值)。
接下来,像0
和1
这样的小数字在内部保存在一个小整数对象池中(这是一个CPython实现细节,不一定是这样!)那是在为foo
分配0
后,0
的ID是相同的。 id基本上是池中整数对象[0, 0, 0]
的id。
如果要在迭代时更改列表,则遗憾的是必须按索引访问元素。因此,如果您想保持输出相同,但最后有for i in range(len(bar)):
print id(bar[i])
bar[i] = 0
print id(bar[i])
print bar
,则必须迭代索引:
{{1}}
否则,它实际上是不可能的,因为只要将列表的元素存储在变量中,就会有一个单独的引用,它与列表中存储的链接无关。由于大多数这些对象都是不可变的,并且在为变量赋值时创建了新对象,因此您无法获得列表对更新的引用。
答案 1 :(得分:3)
是的,你得到的输出是普通的Python行为。为foo
分配新值会更改foo的ID,而不会更改bar
中存储的值。
如果你只想要一个零列表,你可以这样做:
bar = [0] * len(bar)
如果你想做一些更复杂的逻辑,新的赋值取决于旧的值,你可以使用列表理解:
bar = [x * 2 for x in bar]
或者您可以使用map
:
def double(x):
return x * 2
bar = map(double, bar)
答案 2 :(得分:0)
你实际上根本没有更改列表。 循环的第一件事是将bar [0]分配给foo(相当于foo = bar [0])。 foo只是对1的引用。然后你将另一个onject 0分配给foo。这改变了foo的引用为0.但是你没有改变bar [0]。记住,foo作为变量,引用bar [0],但是为foo分配另一个值/对象根本不会影响bar [0]。
答案 3 :(得分:0)
bar = [0 for x in bar]
答案很长:foo
只是一个本地名称,重新绑定不会影响列表。 Python变量实际上只是关键:值对,而不是内存位置的符号名称。