• Python进阶系列 - 19讲 神奇的复制


    在 Python 中,赋值语句 (obj_b = obj_a) 不会创建真正的副本。
    它只创建一个具有相同引用的新变量。
    因此,当您想要制作可变对象(列表、字典)的实际副本并希望在不影响原始对象的情况下修改副本时,您必须小心。
    对于“真实”副本,我们可以使用“复制”模块。
    但是,对于复合/嵌套对象(例如嵌套列表或字典)和自定义对象,有一个重要的复制之间的区别:

    • 浅拷贝:只有 一层深

    它创建一个新的集合对象并使用对嵌套对象的引用来填充它。
    这意味着修改副本中的嵌套对象比一层更深会影响原始对象。

    • 深拷贝:一个 完全独立的克隆
      它创建一个新的集合对象,然后用原始对象中的嵌套对象的副本递归地填充它。

    赋值操作

    这只会创建一个具有相同引用的新变量。
    修改一个会影响另一个。

    代码:

    list_a = [1, 2, 3, 4, 5]
    list_b = list_a
    list_a[0] = -10
    print(list_a)
    print(list_b)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    结果:

    [-10, 2, 3, 4, 5]
    [-10, 2, 3, 4, 5]
    
    • 1
    • 2

    浅复制

    只复制1层。 在级别 1 上进行修改不会影响其他列表。 使用 copy.copy() 或特定于对象的复制函数/复制构造函数

    代码:

    import copy
    list_a = [1, 2, 3, 4, 5]
    list_b = copy.copy(list_a) # 浅复制:list_b 不会影响 list_a
    list_b[0] = -10
    print(list_a)
    print(list_b)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果:

    [1, 2, 3, 4, 5]
    [-10, 2, 3, 4, 5]
    
    • 1
    • 2

    但是对于嵌套对象,在级别 2 或更深的修改确实会影响另一个!

    代码:

    import copy
    list_a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
    list_b = copy.copy(list_a) # 浅复制:list_a 第二层没有复制。
    list_a[0][0]= -10
    print(list_a)
    print(list_b)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果:

            [[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
            [[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
    
    • 1
    • 2

    注意:您还可以使用以下方法创建浅拷贝

    list_b = list(list_a) # list进行copy
    list_b = list_a[:] # [:] 进行copy
    list_b = list_a.copy() # 对象方法进行copy
    
    • 1
    • 2
    • 3

    深复制

    忽略嵌套问题,完全复制!

    代码:

    import copy
    list_a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
    list_b = copy.deepcopy(list_a)
    list_a[0][0]= -10
    print(list_a)
    print(list_b)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果:

    [[-10, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
    [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
    
    • 1
    • 2

    自定义对象的复制

    您可以使用 copy 模块获取自定义对象的浅拷贝或深层拷贝。

    代码:

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    p1 = Person('Alex', 27) #赋值操作
    p2 = p1
    p2.age = 28
    print(p1.age)
    print(p2.age)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果:

    28
    28
    
    • 1
    • 2

    代码:

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    # 浅拷贝
    import copy
    p1 = Person('Alex', 27)
    p2 = copy.copy(p1) #浅拷贝
    p2.age = 28
    print(p1.age)
    print(p2.age)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果:

    27
    28
    
    • 1
    • 2

    让我们看一个嵌套的例子:

    import copy
    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    class Company:
        def __init__(self, boss, employee):
            self. boss = boss
            self.employee = employee
    # 浅拷贝 影响嵌套内容
    boss = Person('Jane', 55)
    employee = Person('Joe', 28)
    company = Company(boss, employee)
    company_clone = copy.copy(company)
    company_clone.boss.age = 56
    print("浅拷贝测试:会影响嵌套内容")
    print(company.boss.age)
    print(company_clone.boss.age)
    
    # 深拷贝 不影响嵌套内容
    boss = Person('Jane', 55)
    employee = Person('Joe', 28)
    company = Company(boss, employee)
    company_clone = copy.deepcopy(company)
    company_clone.boss.age = 56
    print("深拷贝测试:不会影响嵌套内容")
    print(company.boss.age)
    print(company_clone.boss.age)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    结果:

    浅拷贝测试:会影响嵌套内容
    56
    56
    深拷贝测试:不会影响嵌套内容
    55
    56
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    从零开始的python生活02
    python3.7 编译cv_bridge 踩坑记录
    RNN/LSTM (二) 实践案例
    LeetCode 面试题 04.02. 最小高度树
    51单片机学习:LED点阵实验(显示图像)
    Linux—redhat期末作业
    【Shell篇<Ⅴ>】——三剑客之awk
    thinkphp5 扩展redis Linux搭建redis php搭建redis
    全世界 LoRA 训练脚本,联合起来!
    保存滚动位置的实现方法
  • 原文地址:https://blog.csdn.net/pythontip/article/details/127375319