您的位置:

Python深拷贝和浅拷贝

Python是一门强大的解释型语言,支持各种数据类型操作。在 Python 中,当我们需要对于数据结构进行拷贝时,会面临深拷贝和浅拷贝的问题。理解这两种拷贝的概念和使用方法将有助于你在编写 Python 程序时更加灵活地操作变量和数据结构。

一、区分深拷贝和浅拷贝

深拷贝和浅拷贝是 Python 中关于变量拷贝的两个重要概念。深拷贝指的是一次递归地拷贝出新对象和所有子对象,而浅拷贝则指的是一次拷贝对象本身以及对象的子对象,子对象不做拷贝。下面分别从这两种拷贝的概念、用法和区别三个方面来阐述它们的不同。

二、深拷贝和浅拷贝的概念和用法

2.1 深拷贝

深拷贝是将一个对象拷贝到另一个对象,并在新对象中分配新的内存空间,然后将旧对象的内容逐个复制到新对象中。对复杂对象执行深拷贝时,它会将整个对象递归拷贝到新对象中,并分配新内存空间,从而创建一个全新的独立对象。因此,对新对象所做的任何修改都不会影响到旧对象。要执行深拷贝,可以使用 copy 中的 deepcopy 函数。

    import copy

    list_a = [1, [2, 3], [4, 5], 6]
    list_b = copy.deepcopy(list_a)
    list_b[1].append(8)
    list_b.append(10)

    print(list_a)  # [1, [2, 3], [4, 5], 6]
    print(list_b)  # [1, [2, 3, 8], [4, 5], 6, 10]

在上面的例子中,我们首先将 list_a 的内容赋值给 list_b,然后我们对 list_b 修改了第一个列表,并添加了一个新值。最后我们可以看到两个列表是完全独立的对象。深拷贝仅在 Python 中递归深度有限制。

2.2 浅拷贝

浅拷贝是将一个对象的顶层内容拷贝到一个新的对象中,但不会拷贝该顶层内容中的所有子对象,因此两个对象可能共享某些子对象。要执行浅拷贝,可以使用 copy 中的 copy 函数。

    import copy

    list_a = [1, [2, 3], [4, 5], 6]
    list_b = copy.copy(list_a)
    list_b[1].append(8)
    list_b.append(10)

    print(list_a)  # [1, [2, 3, 8], [4, 5], 6]
    print(list_b)  # [1, [2, 3, 8], [4, 5], 6, 10]

在上面的例子中,我们首先将 list_a 的内容赋值给 list_b,然后我们对 list_b 修改了第一个列表,并添加了一个新值。最后我们可以看到两个列表是共享了子对象 [2, 3] 的引用。浅拷贝只限于拷贝对象的一层内容,任意深度的子对象将共享一个引用。

三、深拷贝和浅拷贝的区别

深拷贝和浅拷贝的主要区别在于它们拷贝对象的方式。当对象中包含其他对象的引用时,修改一份拷贝后,另外一份拷贝是否也会受到影响。深拷贝创建的是一个完全独立的对象,不共享任何引用;而浅拷贝,如果发现子对象是引用元素,它就会共享这些子对象的引用。这意味着,如果拷贝对象包含一个引用对象,该引用对象被两个变量分别引用,则只会对其中一个变量进行修改。

    import copy

    list_a = [1, [2, 3], [4, 5], 6]
    list_b = list_a
    list_c = copy.copy(list_a)
    list_d = copy.deepcopy(list_a)

    list_a[0] = 0
    list_a[1].append(7)

    print(list_a)  # [0, [2, 3, 7], [4, 5], 6]
    print(list_b)  # [0, [2, 3, 7], [4, 5], 6]
    print(list_c)  # [1, [2, 3, 7], [4, 5], 6]
    print(list_d)  # [1, [2, 3], [4, 5], 6]

上面的例子中,我们首先使用赋值将 list_a 的内容赋值到 list_b 中,然后我们用浅拷贝将其复制到 list_c 中,最后使用深拷贝将其复制到 list_d 中。然后我们尝试修改 list_a,可以看到该修改会影响 list_b,但不会影响 list_c 和 list_d。

四、总结

本文详细讲述了 Python 中的深拷贝和浅拷贝的概念、用法和区别。要知道如何选取正确的拷贝方式,一个好的编程习惯是首先思考数据结构内部是否包含子对象。如果该数据结构中有子对象,则可能需要使用深拷贝,以避免共享引用和部分修改的问题。如果对象只是包含值对象,则可以使用浅拷贝,因为它不会共享引用。