我想知道如何在Python中使用的一些细节。
我的理解是for var in iterable
每次迭代都会创建一个变量var,绑定到iterable的当前值。因此,如果您执行for c in cows; c = cows[whatever]
,但在循环内更改c不会影响原始值。但是,如果要为字典键分配值,它似乎会有所不同。
cows=[0,1,2,3,4,5]
for c in cows:
c+=2
#cows is now the same - [0,1,2,3,4,5]
cows=[{'cow':0},{'cow':1},{'cow':2},{'cow':3},{'cow':4},{'cow':5}]
for c in cows:
c['cow']+=2
# cows is now [{'cow': 2}, {'cow': 3}, {'cow': 4}, {'cow': 5}, {'cow': 6}, {'cow': 7}
#so, it's changed the original, unlike the previous example
我看到人们可以使用枚举来使第一个例子工作,但我想这是一个不同的故事。
cows=[0,1,2,3,4,5]
for i,c in enumerate(cows):
cows[i]+=1
# cows is now [1, 2, 3, 4, 5, 6]
为什么它会影响第二个示例中的原始列表值,而不影响第一个示例中的原始列表值?
[编辑]
感谢您的回答。我从PHP的角度来看这个,你可以使用& foreach中的符号,用于指定您是对可迭代的引用还是副本进行操作。我现在看到真正的区别是python如何处理不可变对象的基本细节。
答案 0 :(得分:17)
它有助于描绘每次迭代中c
所持有的引用会发生什么:
[ 0, 1, 2, 3, 4, 5 ]
^
|
c
c包含指向列表中第一个元素的引用。执行c += 2
(即c = c + 2
时,临时变量c
会重新分配一个新值。此新值为2
,c
将反弹为这个新值。原始列表是单独的。
[ 0, 1, 2, 3, 4, 5 ]
c -> 2
现在,在字典案例中,这是c
在第一次迭代中绑定的内容:
[ {'cow':0}, {'cow':1}, {'cow':2}, {'cow':3}, {'cow':4}, {'cow':5} ]
^
|
c
此处,c
指向字典对象{'cow':0}
。当您执行c['cow'] += 2
(即c['cow'] = c['cow'] + 2
)时,字典对象本身会发生变化,因为c
不会反弹到不相关的对象。也就是说,c
仍然指向第一个字典对象。
[ {'cow':2}, {'cow':1}, {'cow':2}, {'cow':3}, {'cow':4}, {'cow':5} ]
^
|
c
答案 1 :(得分:5)
实际上并没有采取不同的行动。更改变量与更改变量的属性不同。您将在以下示例中看到相同的内容:
a = 1
b = a
b = 2
这里a仍然是1. b被赋予了不同的值,并且不再与
相同a = {"hello": 1}
b = a
b["hello"] = 2
此处a["hello]
返回2而不是1. b
仍然是相同的值,因为我们没有为b
分配任何内容,因此b
与a
。我们将["hello"]
的属性b
更改为2,因为a
和b
是相同的变量a["hello"]
也是2
答案 2 :(得分:4)
c
都是临时的一次性变量。 (请记住,在Python中,所有变量都只是引用,绑定到它们所代表的对象,并且能够反弹到不同的对象。在这方面,Python比某些其他语言更加一致。)
在列表示例中,每次迭代都会将c
从一个整数重新绑定到另一个整数,而原始列表保持不变。
在你的dict示例中,每次迭代都会访问c
临时绑定的dict,将其中一个dict的成员重新绑定到另一个整数。
在这两种情况下,c
在循环结束时被忽略,但由于您在第二种情况下更改了c
以外的数据结构,因此您会注意到循环时的更改完成。
答案 3 :(得分:4)
这与for ... in ...
无关。在每个示例中将代码从for c in cows:
更改为c = cows[3]
(并在下一行中显示)并查看效果。
在第一个示例中,list元素是int对象;他们是不变的。在第二个例子中,它们是dict对象,它们是可变的。
答案 4 :(得分:3)
在第一个循环中执行名称分配仅重新绑定名称。在第二个循环中执行项目分配会修改现有对象。
答案 5 :(得分:1)
在第二个示例中,您有一个列表 字典对象。 c
引用在循环范围内修改的字典对象。
答案 6 :(得分:1)
无论循环如何,您都必须注意:
some_var = some_object
将名称some_var
绑定到对象some_object
。 some_var
引用的上一个对象(如果有)是未绑定的。
some_var[some_index] = some_object
不绑定/取消绑定some_var
;它只是以下的语法糖:
some_var.__setitem__(some_index, some_object)
显然,some_var
仍指向与之前相同的可索引(序列或映射)对象,该对象刚被修改。