Python将可变变量append至list,如何保证list中原数据不被修改
背景
先来看一段代码
import pysnooper
@pysnooper.snoop('debug.log')
def functionA():
family = {
'father': 'Tony',
'Mother': 'Mercy',
'children': '',
'age': ''
}
children_list = ['Jack','Tom','Peny']
age_list = ['4','8','16']
family_Members = []
for i in range(len(children_list)):
family['children'] = children_list[i]
family['age'] = age_list[i]
family_Members.append(family)
return family_Members
if __name__ == '__main__':
print(functionA())
我理想中的效果是这样的
[{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Jack', 'age': '4'},
{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Tom', 'age': '8'},
{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Peny', 'age': '16'}]
实际是这样的
[{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Peny', 'age': '16'},
{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Peny', 'age': '16'},
{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Peny', 'age': '16'}]
打断点,或者像我使用pysnooper生成一个debug.log,会发现family['children'] = children_list[i]
不仅将family中children的值更新了,同时也将family_Members中family['children']的值修改了
15:16:53.422115 line 15 for i in range(len(children_list)):
New var:....... i = 0
15:16:53.424112 line 16 family['children'] = children_list[i]
Modified var:.. family = {'father': 'Tony', 'Mother': 'Mercy', 'children': 'Jack', 'age': ''}
15:16:53.425107 line 17 family['age'] = age_list[i]
Modified var:.. family = {'father': 'Tony', 'Mother': 'Mercy', 'children': 'Jack', 'age': '4'}
15:16:53.426105 line 18 family_Members.append(family)
Modified var:.. family_Members = [{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Jack', 'age': '4'}]
15:16:53.428099 line 15 for i in range(len(children_list)):
Modified var:.. i = 1
15:16:53.430096 line 16 family['children'] = children_list[i]
Modified var:.. family = {'father': 'Tony', 'Mother': 'Mercy', 'children': 'Tom', 'age': '4'}
Modified var:.. family_Members = [{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Tom', 'age': '4'}]
15:16:53.432089 line 17 family['age'] = age_list[i]
Modified var:.. family = {'father': 'Tony', 'Mother': 'Mercy', 'children': 'Tom', 'age': '8'}
Modified var:.. family_Members = [{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Tom', 'age': '8'}]
15:16:53.434083 line 18 family_Members.append(family)
Modified var:.. family_Members = [{'father': 'Tony', 'Mother': 'Mercy', 'children...Mother': 'Mercy', 'children': 'Tom', 'age': '8'}]
原因分析
首先来了解下append
append是将对象添加到列表末尾
该方法无返回值,但是会修改原来的列表。
OK,可能就是因为我这里family_Members.append是family这个对象导致的,当i=1,对family中的值作修改的时候,family_Members第0个元素上仍是family这个对象,所以也被同步做了修改。
一种解决方法
简单的使用b=a是不可取的,因为对于Python而言,只是多了一个马甲,对象仍是那个对象,所以这里我们需要使用copy.deepcopy
生成一个新的对象
import pysnooper
import copy
@pysnooper.snoop('debug.log')
def functionA():
family = {
'father': 'Tony',
'Mother': 'Mercy',
'children': '',
'age': ''
}
children_list = ['Jack','Tom','Peny']
age_list = ['4','8','16']
family_Members = []
for i in range(len(children_list)):
family1 = copy.deepcopy(family) # 生成一个新的对象
family_Members.append(family1)
family_Members[i]['children'] = children_list[i]
family_Members[i]['age'] = age_list[i]
return family_Members
if __name__ == '__main__':
print(functionA())
运行结果
[{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Jack', 'age': '4'},
{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Tom', 'age': '8'},
{'father': 'Tony', 'Mother': 'Mercy', 'children': 'Peny', 'age': '16'}]
其他
从需求来看,这个代码的实现还是比较笨的,如果有更好的实现算法,希望你能在评论区告诉我~~~