详解Python 克隆对象

  • Post category:Python

Python 中的对象克隆指的是创建一个完全相同的新对象,新对象包含的所有数据与原始对象相同,但是与原始对象没有关联。对象克隆可以通过多种方式实现,包括浅拷贝和深拷贝。

浅拷贝

浅拷贝会复制原始对象中的引用,而不是对象本身。换句话说,新对象仍然引用原始对象中的相同数据,而不是创建一个新副本。为了创建一个浅拷贝,可以使用原始对象的 copy 方法。

示例1:浅拷贝列表

a = [1,2,[3,4]]
b = a.copy()

# 修改原始对象中的第三个元素 
a[2][0] = 5

# 输出新对象和原始对象
print(a)     # [1, 2, [5, 4]]
print(b)     # [1, 2, [5, 4]]

在上面的例子中,a 是一个包含整数和嵌套列表的列表。创建 b 的流程如下:

b = a.copy()

这将创建一个新列表 b,其内容与 a 相同。然后,我们将修改 a 的第三个元素,从原来的 [3, 4] 改成了 [5, 4]。结果,b 的第三个元素也被更改,因为 b 仍然引用 a 中相同的列表。

示例2:浅拷贝自定义对象

我们可以通过定义__copy__()方法来实现自定义对象的浅拷贝,代码如下:

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    def __repr__(self):
        return f"Car({self.make!r}, {self.model!r}, {self.year!r})"

    def __copy__(self):
        return Car(self.make, self.model, self.year)

# 创建两个实例
car1 = Car('Toyota', 'Corolla', 2022)
car2 = car1.__copy__()

# 修改car1
car1.year = 2021

# 输出两个实例
print(car1)     # Car('Toyota', 'Corolla', 2021)
print(car2)     # Car('Toyota', 'Corolla', 2022)

在上面的例子中,我们定义了一个 Car 类,该类有三个属性:makemodelyear。我们还定义了一个 __copy__ 方法,该方法返回一个新的 Car 实例,其属性与原始实例相同。 我们使用 __copy__() 来创建一个新对象 car2,对car1进行修改后,输出结果表明修改没有影响到car2。

深拷贝

与浅拷贝不同,深拷贝会递归地复制对象及其引用的任何对象。这使得新对象的所有数据都是完全独立的,不受原始对象影响。在 Python 中,可以使用 copy 模块中的 deepcopy 函数来进行深拷贝。

示例3:深拷贝列表

import copy

a = [1,2,[3,4]]
b = copy.deepcopy(a)

# 修改原始对象中的第三个元素 
a[2][0] = 5

# 输出新对象和原始对象
print(a)     # [1, 2, [5, 4]]
print(b)     # [1, 2, [3, 4]]

在上面的例子中,deepcopy 函数使用递归方式复制原始对象和其包含的嵌套列表。最终,b 是一个包含相同数据的新列表,但是与 a 完全独立,所以修改 a 中的嵌套列表不会影响 b

示例4:深拷贝自定义对象

我们可以通过定义__deepcopy__()方法来实现自定义对象的深拷贝,代码如下:

import copy

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    def __repr__(self):
        return f"Car({self.make!r}, {self.model!r}, {self.year!r})"

    def __deepcopy__(self, memo):
        return Car(copy.deepcopy(self.make), copy.deepcopy(self.model), copy.deepcopy(self.year))

# 创建两个实例
car1 = Car('Toyota', 'Corolla', [2021, 2022])
car2 = copy.deepcopy(car1)

# 修改car1
car1.year.append(2023)

# 输出两个实例
print(car1)     # Car('Toyota', 'Corolla', [2021, 2022, 2023])
print(car2)     # Car('Toyota', 'Corolla', [2021, 2022])

在上面的例子中,我们通过定义一个 __deepcopy__() 方法来实现一个能够进行深拷贝的 Car 类。在这个方法中,我们使用 copy.deepcopy() 函数递归地复制对象的每个属性。 在这里我们传递了一个 memo 参数,这是一个字典,用于跟踪已经复制的对象,以便避免递归时的无限循环。 我们用 copy.deepcopy() 方法创建新实例 car2,最终的输出表明,修改 car1 后并没有影响 car2