精华内容
下载资源
问答
  • Python深拷贝和浅拷贝使用方法发布时间:2020-06-06 16:52:01来源:亿速云阅读:182这篇文章运用了实例代码展示Python深拷贝和浅拷贝使用方法,代码非常详细,可供感兴趣的小伙伴们参考借鉴,希望对大家有所帮助。...

    Python深拷贝和浅拷贝使用方法

    发布时间:2020-06-06 16:52:01

    来源:亿速云

    阅读:182

    这篇文章运用了实例代码展示Python深拷贝和浅拷贝使用方法,代码非常详细,可供感兴趣的小伙伴们参考借鉴,希望对大家有所帮助。

    一、浅拷贝

    所谓浅拷贝,指的是对于某个对象,虽然创建了与该对象具有相同值的另一个对象,但是,这两个对象內部嵌套的对应子对象全都是同一个对象。简单地说,外部进行了拷贝,内部没有拷贝。

    以下方式得到的拷贝都是浅拷贝:

    ● 切片操作[:]

    ● 调用列表、字典、集合的方法copy()

    ● 调用内置函数List()、dict()、set(4.

    ● 调用标准库模块copy中的函数copy()import copy  # 导入标准库模块copy

    L1 = [1,[1,2,3],6]

    L2 = L1.copy() # [1, [1, 2, 3], 6] 使用list.copy()

    L2 = L1[:] # [1, [1, 2, 3], 6] # 使用索引切片的方式

    L2 = list(L1) #  [1, 2, 3], 6] # 使用list()函数赋值

    L2 = copy.copy(L1) # [1, [1, 2, 3], 6]  # 调用标准库模块copy中的函数copy()

    # 通过打印L1和L2的id可以看出,L2只拷贝了L1的外部,形成了一个和L1具有相同值的对象

    # L1和L2内部值的id全都相同,即引用的同一内存地址

    print('L1_id:%d' % id(L1)) # L1_id:140024932419056

    print('L2_id:%d' % id(L2)) # L2_id:140024932419456

    print('L1[1]_id:%d' % id(L1[1])) # L1[1]_id:140024932419376

    print('L2[1]_id:%d' % id(L2[1])) # L2[1]_id:140024932419376

    print('id_L1[2] %d' % id(L1[2])) # id_L1[2] 9466624

    print('id_L2[2] %d' % id(L2[2])) # id_L2[2] 9466624

    # 浅拷贝,对于列表内部嵌套的可变类型对象,修改L1[1][1]值,L2[1][1]值也会跟着改变

    # 实际上他们内部都引用着同一个内存id

    L1[1][1] = 5

    print(L1) # [1, [1, 5, 3], 6]

    print(L2) # [1, [1, 5, 3], 6]

    print('L1[1]_id:%d' % id(L1[1])) # L1[1]_id:140024932419376

    print('L2[1]_id:%d' % id(L2[1])) # L2[1]_id:140024932419376

    # 浅拷贝,对于列表内部的不可变类型对象,修改L1[2],

    # 因为是不可变类型,那么会重新调用一个值给予引用,L2[2]因此不受影响

    L1[2] = 8

    print(L1) # [1, [1, 5, 3], 8]

    print(L2) # [1, [1, 5, 3], 6]

    print('id_L1[2] %d' % id(L1[2])) # id_L1[2] 9466688

    print('id_L2[2] %d' % id(L2[2])) # id_L2[2] 9466624

    二、深拷贝

    所谓深拷贝,指的是:对于某个对象,创建与该对象具有相同值的另一个对象,同时,这两个对象内部嵌套的对应可变子对象全都不是同一个对象。简单地说,外部和内部都进行了拷贝。

    深拷贝的方法:

    ● 调用标准库模块copy中的函数deepcopy()import copy  # 导入标准库模块copy

    L1 = [1,[1,2,3],6]

    L2 = copy.deepcopy(L1) # [1, [1, 2, 3], 6]

    # 通过打印L1和L2的内存地址可以看出,其外部进行拷贝,L2是和L1具有相同值的新对象

    # 对于内部嵌套的可变类型对象,L1[1]和L2[1]内存地址并不相同

    # 对于内部嵌套的不可变类型对象,L1[2]和L2[2]内存地址相同,引用的同一内存地址

    print('L1_id:%d' % id(L1)) # L1_id:139984573203792

    print('L2_id:%d' % id(L2)) # L2_id:139984573203952

    print('L1[1]_id:%d' % id(L1[1])) # L1[1]_id:139984573203472

    print('L2[1]_id:%d' % id(L2[1])) # L2[1]_id:139984573204512

    print('id_L1[2] %d' % id(L1[2])) # id_L1[2] 9466624

    print('id_L2[2] %d' % id(L2[2])) # id_L2[2] 9466624

    # 深拷贝,列表内部嵌套的可变类型对象,修改L1[1][1] 为5不影响L2[1][1]的值,

    # 深拷贝是将L1和L2内部可变类型对象的值引用的内存地址分开来

    L1[1][1] = 5

    print(L1) # [1, [1, 5, 3], 6]

    print(L2) # [1, [1, 2, 3], 6]

    print('L1[1]_id:%d' % id(L1[1])) # L1[1]_id:139984573203472

    print('L2[1]_id:%d' % id(L2[1])) # L2[1]_id:139984573204512

    # 深拷贝,对于列表内部不可变类型对象,修改L1[2] = 8,因为是不可变类型,所以将L1[2]重新赋值引用,不影响L2[2]

    L1[2] = 8

    print(L1) # [1, [1, 5, 3], 8]

    print(L2) # [1, [1, 2, 3], 6]

    print('id_L1[2] %d' % id(L1[2])) # id_L1[2] 9466688

    print('id_L2[2] %d' % id(L2[2])) # id_L2[2] 9466624

    如果你能读到这里,恭喜你已经对Python深拷贝和浅拷贝有了从实践层面最深刻的体会了。如果想阅读更多相关内容的文章,欢迎关注亿速云行业资讯频道!

    展开全文
  • 对于浅拷贝(shallow copy)深度拷贝(deep copy),本节并不打算一上来抛出它们的概念,而是先从它们的操作方法说起,通过代码来理解两者的不同。list1 = [1, 2, 3]list2 = list(list1)print(list2)print("list1==...

    对于浅拷贝(shallow copy)和深度拷贝(deep copy),本节并不打算一上来抛出它们的概念,而是先从它们的操作方法说起,通过代码来理解两者的不同。

    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)

    运行结果为:

    [1, 2, 3]

    list1==list2 ? True

    list1 is list2 ? False

    {1, 2, 3}

    set1==set2 ? True

    set1 is set2 ? False

    在上面程序中,list2 就是 list1 的浅拷贝,同理 set2 是 set1 的浅拷贝。

    当然,对于可变的序列,还可以通过切片操作符“:”来完成浅拷贝,例如:

    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

    除此之外,Python 还提供了对应的函数 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)

    运行结果为:

    [1, 2, 3]

    list1 == list2 ? True

    list1 is list2 ? False

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

    tuple1 = (1, 2, 3)

    tuple2 = tuple(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) 只被创建一次,t1 和 t2 同时指向这个元组。

    看到这里,也许你可能对浅拷贝有了初步的认识。浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用。

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

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

    此程序中,首先初始化了 list1 列表,包含一个列表和一个元组;然后对 list1 执行浅拷贝,赋予 list2。因为浅拷贝里的元素是对原对象元素的引用,因此 list2 中的元素和 list1 指向同一个列表和元组对象。

    接着往下看,list1.append(100) 表示对 list1 的列表新增元素 100。这个操作不会对 list2 产生任何影响,因为 list2 和 list1 作为整体是两个不同的对象,并不共享内存地址。操作过后 list2 不变,list1 会发生改变。

    再来看,list1[0].append(3) 表示对 list1 中的第一个列表新增元素 3。因为 list2 是 list1 的浅拷贝,list2 中的第一个元素和 list1 中的第一个元素,共同指向同一个列表,因此 list2 中的第一个列表也会相对应的新增元素 3。

    最后是 list1[1] += (50, 60),因为元组是不可变的,这里表示对 list1 中的第二个元组拼接,然后重新创建了一个新元组作为 list1 中的第二个元素,而 list2 中没有引用新元组,因此 list2 并不受影响。

    通过这个例子,你可以很清楚地看到使用浅拷贝可能带来的副作用。如果想避免这种副作用,完整地拷贝一个对象,就需要使用深拷贝。所谓深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联。

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

    可以看到,无论 list1 如何变化,list2 都不变。因为此时的 list1 和 list2 完全独立,没有任何联系。

    不过,深度拷贝也不是完美的,往往也会带来一系列问题。如果被拷贝对象中存在指向自身的引用,那么程序很容易陷入无限循环,例如:

    import copy

    list1 = [1]

    list1.append(list1)

    print(list1)

    list2 = copy.deepcopy(list1)

    print(list2)

    运行结果为:

    [1, [...]]

    [1, [...]]

    此例子中,列表 x 中有指向自身的引用,因此 x 是一个无限嵌套的列表。但是当深度拷贝 x 到 y 后,程序并没有出现栈溢出的现象。这是为什么呢?

    其实,这是因为深度拷贝函数 deepcopy 中会维护一个字典,记录已经拷贝的对象与其 ID。拷贝过程中,如果字典里已经存储了将要拷贝的对象,则会从字典直接返回。通过查看 deepcopy 函数实现的源码就会明白:

    def deepcopy(x, memo=None, _nil=[]):

    """Deep copy operation on arbitrary Python objects.

    See the module's __doc__ string for more info.

    """

    if memo is None:

    memo = {}

    d = id(x) # 查询被拷贝对象 x 的 id

    y = memo.get(d, _nil) # 查询字典里是否已经存储了该对象

    if y is not _nil:

    return y # 如果字典里已经存储了将要拷贝的对象,则直接返回

    ...

    展开全文
  • Python 深拷贝和浅拷贝的区别

    千次阅读 2020-02-10 19:26:18
    Python拷贝和浅拷贝的区别 深浅拷贝在python中经常使用,其区别的外在表现是: 使用浅拷贝,当原容器对象中可变对象中有元素发生变化,拷贝得到的对象也会变化。而使用深拷贝时,不会有这种问题。 浅拷贝: # -*-...

    Python 深拷贝和浅拷贝的区别

    深浅拷贝在python中经常使用,其区别的外在表现是:

    使用浅拷贝,当原容器对象中可变对象中有元素发生变化,拷贝得到的对象也会变化。而使用深拷贝时,不会有这种问题。

    浅拷贝:

    # -*- coding: utf-8 -*-
    # @File   : 浅拷贝.py
    # @Author : Runpeng Zhang
    # @Date   : 2020/2/10
    # @Desc   : 演示介绍深拷贝和浅拷贝的区别,该文件演示浅拷贝
    # copy浅拷贝,没有拷贝子对象,所以原始数据改变,子对象会改变
    
    
    import copy
    
    # 定义一个列表,其中第一个元素是可变类型
    list1 = [[1, 2], 'fei', 66]
    # 进行浅copy
    list2 = copy.copy(list1)
    
    # 对象地址是否相同
    print(id(list1))
    print(id(list2))
    """
    对象的地址是不同的
    2313807246344
    2313789591048
    """
    
    # 第一个元素地址是否相同
    print(id(list1[0]))
    print(id(list2[0]))
    """
    结果是相同的
    2313807270216
    2313807270216
    """
    
    # 第二个元素地址是否相同
    print(id(list1[1]))
    print(id(list2[1]))
    """
    结果是相同的
    2313789572576
    2313789572576
    """
    
    # 改变第一个值,查看复制对象变化
    list1[0][0] = 2
    print(list2)
    """
    结果是复制对象也发生了变化[[2, 2], 'fei', 66]
    """
    
    # 改变第二个值,查看复制对象变化
    list1[1] = 'ge'
    print(list2)
    """
    结果是复制对象没发生变化[[2, 2], 'fei', 66]
    """
    
    

    深拷贝

    # -*- coding: utf-8 -*-
    # @File   : 深拷贝.py
    # @Author : Runpeng Zhang
    # @Date   : 2020/2/10
    # @Desc   : 演示介绍深拷贝和浅拷贝的区别,该文件演示深拷贝
    # 深拷贝,包含对象里面的自对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
    
    
    import copy
    
    # 定义一个列表,其中第一个元素是可变类型
    list1 = [[1, 2], 'fei', 66]
    # 进行深copy
    list2 = copy.deepcopy(list1)
    
    # 对象地址是否相同
    print(id(list1))
    print(id(list2))
    """
    对象的地址是不同的
    2313807246344
    2313789591048
    """
    
    # 改变第一个值,查看复制对象变化
    list1[0][0] = 2
    print(list2)
    """
    结果是复制对象始终没有发生变化[[1, 2], 'fei', 66]
    """
    
    # 改变第二个值,查看复制对象变化
    list1[1] = 'ge'
    print(list2)
    """
    结果是复制对象始终没有发生变化[[2, 2], 'fei', 66]
    """
    
    

    分析

    当我们声明list1 = [[‘a’, ‘b’], 1, 2]时,计算机做了这些事:

    1、在内存中开辟一段空间,用来存放字符a,b和数字1,数字2

    2、在内存开辟一段空间,用来存放一个列表,我们称为list2。list2中存放两个指针,分别指向字符a和b

    3、在内存开辟一段空间,用来存放一个列表lsit1,list1中存放三个指针,分别指向list2,数字1和数字2

    当执行浅拷贝lsit3 = copy.copy(list1)时,计算机开辟一段内存给list3,list3保存三个指针,分别指向list2,数字1和数字2。当执行list1[0][0] = 'c’时,list2对象修改了,而list3的第一个指针指向list2,所以我们看到list3的第一个元素也变了。

    当执行深拷贝lsit4 = copy.copy(list1)时,计算机开辟一段内存给list4,和浅拷贝不同的是,计算机同时开辟一段空间给新的列表,我们称为lsit5。list5中保存2个指针,分别指向字符a和b。

    同时list4保存三个指针,分别指向list5,数字1和数字2。此时,当执行list1[0][0] = 'c’时,list2对象修改了,但list4的第一个指针指向list5,list5并没有修改,所以list4没有改变。

    总结:深拷贝会把可变对象也拷贝一份,而浅拷贝不会。

    上面例子中说的是列表(可变对象)的拷贝,那对于元组,字符等不可不对象呢?

    答案是,对不可不对象,其实不存在深浅拷贝的问题。无论怎么拷贝,效果都是新建立一个指向不可变对象的指针而已。

    展开全文
  • 本文实例讲述了Python深拷贝浅拷贝用法。分享给大家供大家参考,具体如下: 1、对象的赋值 对象的赋值实际上是对象之间的引用:当创建一个对象,然后将这个对象赋值给另外一个变量的时候,python并没有拷贝这个...
  • python深拷贝和浅拷贝

    2021-01-14 15:45:38
    True >>> a is b # a、b分别指向不同的对象 False >>> a is c # a、c指向同一个对象 True 深拷贝:复制了引用内容 浅拷贝: 仅复制了引用,未复制对象 # 浅拷贝 a、b指向同一个对象地址 >>> a = [1,2] >>> b = a >...

    is 比较两个引用是否指向同一个对象

    == 比较两个对象是否相等

    >>> a = [1,2]

    >>> b = [1,2]

    >>> c = a

    >>> id(a)

    140275902517640

    >>> id(b)

    140275902517960

    >>> id(c)

    140275902517640

    >>> a == b # a、b分别指向的对象值相等

    True

    >>> a is b # a、b分别指向不同的对象

    False

    >>> a is c # a、c指向同一个对象

    True

    深拷贝:复制了引用和内容

    浅拷贝: 仅复制了引用,未复制对象

    # 浅拷贝 a、b指向同一个对象地址

    >>> a = [1,2]

    >>> b = a

    >>> id(a)

    140275902517704

    >>> id(b)

    140275902517704

    >>> a.append(3) # 浅拷贝,修改a的值,b的值随之变化 【图1】

    >>> b

    [1,2,3]

    # 深拷贝

    >>> import copy

    >>> c = copy.deepcopy(a)

    >>> id(a)

    140275902517704

    >>> id(c)

    140275902301264

    >>> a.append(3) # 深拷贝,修改a的值,c的值不变 【图2】

    >>> c

    [1,2]

    >>> a = [1,2] # 【图3】

    >>> b = [3,4]

    >>> c = [a,b]

    >>> d = copy.deepcopy(c)

    >>> d

    [[1,2],[3,4]]

    >>> a.append(3)

    >>> c

    [[1,3],4]] # 浅拷贝

    >>> d

    [[1,4]] # 深拷贝

    >>> a = [1,2] # 【图4】

    >>> b = [3,b]

    >>> d = copy.copy(c)

    >>> d

    [[1,4]]

    >>> a[0] = 0

    >>> d

    [[0,4]]

    # copy当拷贝一个不可变类型数据时,只会进行浅拷贝

    a = [1,2]

    b = [3,4]

    c = (a,b)

    d = copy.copy(c)

    展开全文
  • Python 深拷贝和浅拷贝

    2020-12-23 18:09:02
    一、熟悉Python内存管理在Python中,变量在第一次赋值时自动声明,在创建---也就是赋值的时候,解释器会根据语法右侧的操作数来决定新对象的类型。引用计数器:一个内部跟踪变量引用计数:每一个对象各有多少个...
  • 一文了解Python深拷贝浅拷贝问题

    千次阅读 多人点赞 2019-03-01 12:36:29
    在平时工作中,经常涉及到数据的传递,在数据传递使用过程中,可能会发生数据被修改的问题。...今天就说一下Python中的深拷贝浅拷贝的问题。 概念普及:对象、可变类型、引用 数据拷贝会涉...
  • 一、首先深拷贝和浅拷贝都是对原对象的拷贝,都会生成一个看起来相同的对象,本质区别就是拷贝出来的对象的「地址」是否与原对象一样,即就是对原对象的地址的拷贝,还是值的拷贝 深拷贝:对原对象的地址的拷贝,新...
  • 概述深浅拷贝用法来自copy模块导入模块: import copy浅拷贝: copy.copy深拷贝: copy.deepcopy字面理解直接赋值: 其实就是对象的引用(别名),赋值的两边指向的是同一个对象浅拷贝(copy): 拷贝父对象,不会拷贝对象的...
  • 浅拷贝可变类型浅拷贝copy函数就是浅拷贝,只对可变类型的第一层对象进行拷贝,对拷贝的对象开辟新的内存空间...[a, b]普通赋值data_mycopy = data -- datadata_mycopy指向同一片空间浅拷贝data_copy = copy.co...
  • Python深拷贝和浅拷贝

    2021-03-15 16:46:22
    项目场景: import copy c=[1,2,3,5,6,[10,12,13]] d=c#浅拷贝 f=copy.deepcopy(c)#深拷贝...之前学python没有遇到深拷贝和浅拷贝的问题,直到 import copy c=[1,2,3,5,6,[10,12,13]] d=copy.copy(c) #浅拷贝 c.append
  • python深拷贝与浅拷贝 引言 前两天在用python写A*算法的时候,被python的深拷贝和浅拷贝恶搞了一番,实际上还是因为没搞清楚哪些是深拷贝,哪些是浅拷贝,...为什么要区分浅拷贝和深拷贝 这就是一个蛋疼的问题了。以
  • python的复制,深拷贝和浅拷贝的区别

    万次阅读 多人点赞 2019-06-05 09:43:49
    python的复制,深拷贝和浅拷贝的区别 在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有三种方法, alist=...
  • 变量-引用-对象(可变对象,不可变对象)-切片-拷贝(浅拷贝深拷贝) 【变量-对象-引用】 在Python中一切都是对象,比如说:3, 3.14, ‘Hello’, [1,2,3,4],{‘a’:1}…… 甚至连type其本身都是对象,type对象 Python...
  • python:深拷贝,浅拷贝,赋值引用

    万次阅读 多人点赞 2019-05-23 21:08:15
    1. python的复制,深拷贝和浅拷贝的区别 在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有三种方法, a...
  • title: python 深拷贝和浅拷贝tags: python,copy,deepcopygrammar_cjkRuby: true---python 深拷贝和浅拷贝python的变量的赋值都是引用把一个变量赋值给一个变量,不是拷贝这个对象,而是拷贝这个变量的引用直接赋值...
  • Python中深拷贝与浅拷贝的区别:

    万次阅读 多人点赞 2017-04-20 16:58:35
    Python中深拷贝与浅拷贝的区别:
  • 浅拷贝copy模块里面的copy方法实现。浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象;改变原始对象中为不可变类型的元素的值,不会响拷贝对象。python学习网,大量的免费python视频教程,欢迎...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,635
精华内容 9,854
关键字:

python深拷贝和浅拷贝

python 订阅