Python 深拷贝和浅拷贝详解

文章目录

  • 1、Python 深拷贝和浅拷贝概念理解
  • 2、浅拷贝
  • 2.1 使用数据类型本身的构造器
  • 2.2 对于列表
  • 2.3 使用 copy.copy() 函数
  • 2.4 对于元组
  • 2.5 关于切片操作符 ':'
  • 2.6 和赋值的区别
  • 2.7 浅拷贝需注意的问题
  • 2、深拷贝
  • 1、Python 深拷贝和浅拷贝概念理解

  • 浅拷贝,指的是重新分配一块内存创建一个新的对象,但里面的元素是原对象中各个子对象的引用

  • 深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联

  • 2、浅拷贝

  • 使用数据类型本身的构造器
  • 对于可变的序列,还可以通过切片操作符 : 来完成浅拷贝
  • Python 还提供了对应的函数 copy.copy() 函数,适用于任何数据类型
  • 2.1 使用数据类型本身的构造器

    list1 = [1, 2, 3]
    list2 = list(list1)
    print(list2)
    print("list1==list2 ?",list1==list2)
    print("list1 is list2 ?",list1 is list2)
    
    set1= set([1, 2, 3])
    set2 = set(set1)
    print(set2)
    print("set1==set2 ?",set1==set2)
    print("set1 is set2 ?",set1 is set2)
    
    dict1 = {1:[1,'w'], 2:0, 3:98}
    dict2 = dict(dict1)
    print(dict2)
    print("dict1 == dict2 ?",dict1 == dict2)
    print("dict1 is dict2 ?",dict1 is dict2)
    
    [1, 2, 3]
    list1==list2 ? True
    list1 is list2 ? False
    
    {1, 2, 3}
    set1==set2 ? True
    set1 is set2 ? False
    
    {1: [1, 'w'], 2: 0, 3: 98}
    dict1 == dict2 ? True
    dict1 is dict2 ? False
    

    分析: 浅拷贝,为新变量重新分配一块内存,和原来变量的内存不一样,所以有

    list1 is list2 ? False
    set1 is set2 ? False
    dict1 is dict2 ? False
    

    但浅拷贝完,两个变量中的元素的值是一样的。

    list1==list2 ? True
    dict1 == dict2 ? True
    set1==set2 ? True
    

    2.2 对于列表

    对于列表,还可以通过切片操作符“:”来完成浅拷贝

    list1 = [1, 2, 3]
    list2 = list1[:]
    print(list2)
    print("list1 == list2 ?",list1 == list2)
    print("list1 is list2 ?",list1 is list2)
    
    [1, 2, 3]
    list1 == list2 ? True
    list1 is list2 ? False
    

    2.3 使用 copy.copy() 函数

    函数 copy.copy() 函数,适用于任何数据类型

    import copy
    
    list1 = [1, 2, 3]
    list2 = copy.copy(list1)
    print(list2)
    print("list1 == list2 ?",list1 == list2)
    print("list1 is list2 ?",list1 is list2)
    
    set1 = {1, 2, 3}
    set2 = copy.copy(set1)
    print(set2)
    print("set1 == set2 ?",set1 == set2)
    print("set1 is set2 ?",set1 is set2)
    
    dict1 = {1:'xiaoming', 2:'xiahua',3:'xiaoli'}
    dict2 = dict(dict1)
    print(dict2)
    print("dict1 == dict2 ?",dict1 == dict2)
    print("dict1 is dict2 ?",dict1 is dict2)
    
    [1, 2, 3]
    list1 == list2 ? True
    list1 is list2 ? False
    
    {1, 2, 3}
    set1 == set2 ? True
    set1 is set2 ? False
    
    {1: 'xiaoming', 2: 'xiahua', 3: 'xiaoli'}
    dict1 == dict2 ? True
    dict1 is dict2 ? False
    

    2.4 对于元组

    对于元组,使用 tuple() 或者切片操作符 ‘:’ 不会创建一份浅拷贝,相反它会返回一个指向相同元组的引用:

    tuple1 = (1, 2, 3)
    tuple2 = tuple(tuple1)
    print(tuple2)
    print("tuple1 == tuple2 ?",tuple1 == tuple2)
    print("tuple1 is tuple2 ?",tuple1 is tuple2)
    
    tuple1 = (1, 2, 3)
    tuple2 = tuple1[:]
    print(tuple2)
    print("tuple1 == tuple2 ?",tuple1 == tuple2)
    print("tuple1 is tuple2 ?",tuple1 is tuple2)
    
    (1, 2, 3)
    tuple1 == tuple2 ? True
    tuple1 is tuple2 ? True
    
    (1, 2, 3)
    tuple1 == tuple2 ? True
    tuple1 is tuple2 ? True
    

    使用 tuple() 或者切片操作符 ‘:’ 不会创建一份浅拷贝,因为它开辟新的内存存储的是原对象的引用,而没有创建新的对象来存储原对象的子对象的引用,所以不是浅拷贝。相反它会返回一个指向相同元组的引用。

    对字符串使用 str() 或者切片操作符 ‘:’,原理和 元组相同。

    str1 = 'operation'
    str2 = str1[:]
    print(str2)
    print("str1 == str2 ?",str1 == str2)
    print("str1 is str2 ?",str1 is str2)
    
    operation
    str1 == str2 ? True
    str1 is str2 ? True
    
    str1 = 'operation'
    str2 = str(str1)
    print(str2)
    print("str1 == str2 ?",str1 == str2)
    print("str1 is str2 ?",str1 is str2)
    
    operation
    str1 == str2 ? True
    str1 is str2 ? True
    
    import copy
    
    set1 = (1, 2, 3)
    set2 = copy.copy(set1)
    print(set2)
    print("set1 == set2 ?",set1 == set2)
    print("set1 is set2 ?",set1 is set2)
    
    (1, 2, 3)
    set1 == set2 ? True
    set1 is set2 ? True
    
    import copy
    
    set1 = 'operation'
    set2 = copy.copy(set1)
    print(set2)
    print("set1 == set2 ?",set1 == set2)
    print("set1 is set2 ?",set1 is set2)
    
    operation
    set1 == set2 ? True
    set1 is set2 ? True
    

    也就是说,对字符串和元组使用 copy()、[:]、本身的构造器完成的复制,都只是开辟了内存存储原对象的引用,而不是存储原对象的子对象的引用。

    2.5 关于切片操作符 ‘:’

    切片操作符 ‘:’ 不能用于字典和集合完成浅拷贝

    # set1 = {1, 2, 3}
    # set2 = set1[:]
    
    # dict1 = {1:1, 2:2, 3:3}
    # dict2 = dict1[:]
    

    2.6 和赋值的区别

    和赋值的本质区别在于,赋值只是把原对象的引用给到新对象

    set1 = {1:1, 2:2, 3:3}
    set2 = set1
    print(set2)
    print("set1 == set2 ?",set1 == set2)
    print(id(set1))
    print(id(set2))
    
    {1: 1, 2: 2, 3: 3}
    set1 == set2 ? True
    2515252654368
    2515252654368
    

    2.7 浅拷贝需注意的问题

    对数据采用浅拷贝的方式时,如果原对象中的元素不可变,那倒无所谓;但如果元素可变,浅拷贝通常会出现一些问题,

    list1 = [[1, 2], (30, 40)]
    list2 = list(list1)
    list1.append(100)
    print("list1:",list1)
    print("list2:",list2)
    list1[0].append(3)
    print("list1:",list1)
    print("list2:",list2)
    list1[1] += (50, 60)
    print("list1:",list1)
    print("list2:",list2)
    
    list1: [[1, 2], (30, 40), 100]
    list2: [[1, 2], (30, 40)]
    list1: [[1, 2, 3], (30, 40), 100]
    list2: [[1, 2, 3], (30, 40)]
    list1: [[1, 2, 3], (30, 40, 50, 60), 100]
    list2: [[1, 2, 3], (30, 40)]
    

    2、深拷贝

    Python 中以 copy.deepcopy() 来实现对象的深度拷贝

    import copy
    
    list1 = [[1, 2], (30, 40)]
    list2 = copy.deepcopy(list1)
    
    list1.append(100)
    print("list1:",list1)
    print("list2:",list2)
    
    list1[0].append(3)
    print("list1:",list1)
    print("list2:",list2)
    
    list1[1] += (50, 60)
    print("list1:",list1)
    print("list2:",list2)
    
    list1: [[1, 2], (30, 40), 100]
    list2: [[1, 2], (30, 40)]
    list1: [[1, 2, 3], (30, 40), 100]
    list2: [[1, 2], (30, 40)]
    list1: [[1, 2, 3], (30, 40, 50, 60), 100]
    list2: [[1, 2], (30, 40)]
    

    来源:xzw96

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

    发表评论