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'}]

其他

从需求来看,这个代码的实现还是比较笨的,如果有更好的实现算法,希望你能在评论区告诉我~~~

posted @ 2021-06-18 17:22  晓天的BigWorld  阅读(487)  评论(0编辑  收藏  举报