python 的引用问题

先看错误示范:

1
2
3
4
5
6
7
8
9
person = {'name': '', 'ids': 0}
team = []

for i in range(3):
x = person
x['ids'] = i
team.append(x)
print(team)
>>>[{'name': '', 'ids': 2}, {'name': '', 'ids': 2}, {'name': '', 'ids': 2}]

可能一眼看不出结果为什么不是自己相象的那样,我们在中间穿插一些print来 debug 下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
person = {'name': '', 'ids': 0}
team = []
for i in range(3):
    x = person
x['ids'] = i
print(id(x),x)
team.append(x)
print(team)
>>>
33373712 {'name': '', 'ids': 0}

33373712 {'name': '', 'ids': 1}

33373712 {'name': '', 'ids': 2}

[{'name': '', 'ids': 2}, {'name': '', 'ids': 2}, {'name': '', 'ids': 2}]

我们可以看到 x 的 id 在循环中并没有发生变化,但是 x 的值却在循环中因为x['ids'] = i的赋值发生了变化。这样导致的结果便是 team 列表中3 个 append x 的元素都会变成循环中最后一次的赋值。究其原因就是在循环中 x 一直在引用 person的值。

解决方法1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from copy import deepcopy
person = {'name': '', 'ids': 0}

team = []
for i in range(3):
x = deepcopy(person) #使用deepcopy,改变x的id

x['ids'] = i
print(id(x),x)

    team.append(x)
print(team)
>>>
45083456 {'name': '', 'ids': 0}

42706336 {'name': '', 'ids': 1}

45195840 {'name': '', 'ids': 2}

[{'name': '', 'ids': 0}, {'name': '', 'ids': 1}, {'name': '', 'ids': 2}]

解决方法2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
team = []
for i in range(3):
person = {'name': '', 'ids': 0} #直接定义变量(不引用还不行?)

person['ids']=i
print(id(person),person)

    team.append(person)
print(team)
>>>
37436944 {'name': '', 'ids': 0}
37437016 {'name': '', 'ids': 1}
37474376 {'name': '', 'ids': 2}
[{'name': '', 'ids': 0}, {'name': '', 'ids': 1}, {'name': '', 'ids': 2}]