Python append() 添加嵌套的可变对象

Python list 进行循环 append() 操作时,如果追加的是可变对象,可用 copy() 进行浅拷贝;如果追加的对象里有嵌套的可变对象,则需用深拷贝 copy.deepcopy() 来解决。赋值、浅拷贝和深拷贝的区别,也是个极易让 Python 初学者掉进去的坑。
如下代码:

    a = []  # 空列表
    b = {  # 准备添加到列表a中的字典
        'A': 111,
        'B': 222
    }
    
    a.append(b)
    # 此时打印列表a:[{'A': 111, 'B': 222}]
    b['A'] = 333
    # 修改字典b后,列表a也发生了变化:[{'A': 333, 'B': 222}]

因为,Python 中对 list 进行 append(x) 操作添加一个对象 x 时,实际上是追加了一个 x 对象的引用。 如果 x 是列表、字典、集合等可变对象,修改 x 值后,list 对象的值也发生变化。

再来试试一个循环 append() 操作:

    a = []  # 空列表
    b = {}  # 空字典
    # 用for循环把字典b逐一添加到列表a中
    for i in range(3):
        b['AAA'] = i + 1
        print(b)
        a.append(b)
        
    print(a)
    # 每次打印字典b,分别为:
    # {'AAA': 1}
    # {'AAA': 2}
    # {'AAA': 3}
    # 但最后打印列表a为: [{'AAA': 3}, {'AAA': 3}, {'AAA': 3}],与想象中的不一样。
    # 因为每次i递增时都会导致之前的字典中的value发生变化。
    
    
    # 这里用浅拷贝即可达到想要的效果,如下:
    a = []  # 空列表
    b = {}  # 空字典
    for i in range(3):
        b['AAA'] = i + 1
        a.append(b.copy())
    
    print(a)
    # 现在列表a是 [{'AAA': 1}, {'AAA': 2}, {'AAA': 3}]

使用浅拷贝(copy):只会拷贝父对象,不会拷贝对象内部的子对象,如果拷贝的是嵌套的可变对象,则又会出现与上面不同的结果,此时就需要深拷贝了。 copy 模块的 deepcopy (深拷贝)方法,完全拷贝了父对象及其子对象。 如下代码:

    a = []  # 空列表
    b = {  # 嵌套字典
        'AAA': {},
    }
    for i in range(3):
        b['AAA']['aaa'] = i + 1
        print(b)
        a.append(b.copy())
    
    print(a)
    # {'AAA': {'aaa': 1}}
    # {'AAA': {'aaa': 2}}
    # {'AAA': {'aaa': 3}}
    # [{'AAA': {'aaa': 3}}, {'AAA': {'aaa': 3}}, {'AAA': {'aaa': 3}}]
    # 现在b是个嵌套的字典,使用浅拷贝时没有得到想要的结果。i递增时还是会导致之前的字典中的value发生变化。
    
    
    # 使用深拷贝即可。需先导入copy模块
    import copy
    
    a = []  # 空列表
    b = {  # 嵌套字典
        'AAA': {},
    }
    for i in range(3):
        b['AAA']['aaa'] = i + 1
        a.append(copy.deepcopy(b))
    
    print(a)
    # 结果:[{'AAA': {'aaa': 1}}, {'AAA': {'aaa': 2}}, {'AAA': {'aaa': 3}}]

最后,复制网上一段关于深拷贝与浅拷贝的区别

深拷贝是指使用一块新的与原对象相同大小的内存,将需要拷贝的对象的所有值都拷贝到新的内存位置中,拷贝出来的对象与原对象互相独立。使用深拷贝赋值,传的是值。

浅拷贝是指使用原对象的引用作为拷贝的对象,而不使用新的内存存放拷贝出来的对象,拷贝的对象与原对象共用同一块内存,所以对其中任一个做修改,另一个也会随之改变。使用浅拷贝赋值,传的是引用。

参考资料:

Python append() 与深拷贝、浅拷贝

Python避坑:append()函数与浅拷贝

Python中的赋值(复制)、浅拷贝与深拷贝

» 链接地址:https://wbt5.com/python-append-deepcopy.html »英雄不问来路,转载请注明出处。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注