Python 的深拷贝与浅拷贝详解

在 Python 中,拷贝(copy)是指创建一个对象的副本。根据复制的深度,Python 提供了两种类型的拷贝:浅拷贝(shallow copy)和深拷贝(deep copy)。理解它们之间的区别对于避免程序中的潜在错误至关重要,尤其是在涉及到可变对象(如列表、字典、集合等)时。


1. 浅拷贝(Shallow Copy)

浅拷贝是指创建一个新的对象,但是对于原对象中包含的引用类型(如列表中的其他列表),不会创建新的副本,而是直接引用原对象中的内容。简而言之,浅  拷贝仅复制对象本身,并没有递归地复制对象内部的元素。

浅拷贝的工作原理
  • 对于原对象中的基本数据类型(如整数、浮点数、字符串等),会创建一份副本。
  • 对于原对象中的可变数据类型(如列表、字典等),浅拷贝会保持原对象内部元素的引用,即原对象和副本指向相同的内存位置。
  • 如何进行浅拷贝?

    可以使用以下几种方法来创建浅拷贝:

  • copy.copy():标准库中提供的浅拷贝函数。
  • 切片(Slicing):对于列表,可以通过切片语法来生成浅拷贝。
  • dict.copy():对于字典,可以直接调用 copy() 方法。
  • 示例:
    import copy
    
    # 浅拷贝:使用 copy.copy() 创建副本
    original_list = [1, 2, [3, 4]]
    shallow_copy = copy.copy(original_list)
    
    print(original_list)  # 输出: [1, 2, [3, 4]]
    print(shallow_copy)   # 输出: [1, 2, [3, 4]]
    
    # 修改浅拷贝中的嵌套列表
    shallow_copy[2][0] = 99
    
    print(original_list)  # 输出: [1, 2, [99, 4]],原对象中的嵌套列表也发生了变化
    print(shallow_copy)   # 输出: [1, 2, [99, 4]],副本中的嵌套列表也发生了变化
    

    在上面的例子中,original_listshallow_copy 拥有相同的嵌套列表 [3, 4],修改嵌套列表的内容时,原对象和浅拷贝都会受影响。这是因为浅拷贝仅复制了外部列表,内部的嵌套列表仍然指向相同的内存位置。

    浅拷贝的限制
  • 只拷贝最外层的对象,内部的可变对象会共享。
  • 对于嵌套的可变对象,修改内部对象时,原始对象和副本都会发生变化。

  • 2. 深拷贝(Deep Copy)

    深拷贝是指创建一个新的对象,并且递归地复制原对象中的所有元素及其内部的可变对象。换句话说,深拷贝不仅复制对象本身,还复制对象内部的所有元素,直到所有嵌套对象都被完全复制为止。

    深拷贝的工作原理
  • 对于所有类型的对象(包括嵌套的可变对象),都会创建新的副本。
  • 不会共享任何引用。每个对象及其嵌套对象都会有独立的内存空间。
  • 如何进行深拷贝?
  • copy.deepcopy():标准库中提供的深拷贝函数。
  • 示例:
    import copy
    
    # 深拷贝:使用 copy.deepcopy() 创建副本
    original_list = [1, 2, [3, 4]]
    deep_copy = copy.deepcopy(original_list)
    
    print(original_list)  # 输出: [1, 2, [3, 4]]
    print(deep_copy)      # 输出: [1, 2, [3, 4]]
    
    # 修改深拷贝中的嵌套列表
    deep_copy[2][0] = 99
    
    print(original_list)  # 输出: [1, 2, [3, 4]],原对象没有改变
    print(deep_copy)      # 输出: [1, 2, [99, 4]],副本中的嵌套列表已改变
    

    在这个例子中,original_listdeep_copy 是完全独立的,即使修改了 deep_copy 中的嵌套列表,original_list 不会受到任何影响。

    深拷贝的特点
  • 创建独立的副本,所有嵌套的对象也会被递归复制。
  • 无论对象的结构多复杂,副本和原对象之间完全没有联系。

  • 3. 浅拷贝与深拷贝的区别

    特性 浅拷贝(Shallow Copy) 深拷贝(Deep Copy)
    复制对象 仅复制最外层对象 复制最外层对象及所有嵌套对象
    嵌套对象是否复制 嵌套对象仍然引用原对象中的元素 嵌套对象会被完全复制
    内部对象的修改是否影响原对象 修改内部对象会影响原对象和副本 修改副本的嵌套对象不会影响原对象
    创建副本的时间 速度较快,拷贝过程较简单 速度较慢,需要递归遍历每一层嵌套对象
    示例:
    import copy
    
    # 浅拷贝
    original = {'a': 1, 'b': [1, 2, 3]}
    shallow = copy.copy(original)
    shallow['b'][0] = 99
    
    print(original)  # 输出: {'a': 1, 'b': [99, 2, 3]}
    print(shallow)   # 输出: {'a': 1, 'b': [99, 2, 3]},修改共享的列表
    
    # 深拷贝
    deep = copy.deepcopy(original)
    deep['b'][1] = 100
    
    print(original)  # 输出: {'a': 1, 'b': [99, 2, 3]}
    print(deep)       # 输出: {'a': 1, 'b': [99, 100, 3]},修改副本不会影响原对象
    

    4. 什么时候使用浅拷贝和深拷贝

  • 浅拷贝适用于你只关心外部对象的拷贝,不需要完全独立的内部对象副本时。浅拷贝的性能相对较好,适用于对象结构较简单或嵌套层级较浅的情况。
  • 深拷贝适用于当你需要创建一个完全独立的副本,确保原对象和副本之间没有任何共享的引用时。深拷贝适用于复杂嵌套对象的复制,但其性能相对较低。

  • 5. 总结

  • 浅拷贝仅复制最外层对象,并且内部的可变对象仍然共享引用。适用于对象内部元素不需要完全独立时。
  • 深拷贝会递归地复制所有对象,确保副本和原对象完全独立。适用于需要完整独立副本的场景。
  • 理解浅拷贝和深拷贝的差异,有助于避免因共享可变对象而导致的错误,特别是在处理复杂数据结构时。

    作者:威桑

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python 的深拷贝与浅拷贝详解

    发表回复