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

130 阅读3分钟

在 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)

结果:

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

浅复制

只复制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]
[-10, 2, 3, 4, 5]

但是对于嵌套对象,在级别 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)

结果:

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

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

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

深复制

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

代码:

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)

结果:

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

自定义对象的复制

您可以使用 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)

结果:

28
28

代码:

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)

结果:

27
28

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

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)

结果:

浅拷贝测试:会影响嵌套内容
56
56
深拷贝测试:不会影响嵌套内容
55
56