• [python][进阶之路]理解python中的深复制和浅复制


    简介

    在上一篇关于list的复制中的问题中,笔者提到了一些由于list的复制语句产生的问题,如果能够搞明白一切皆对象的py设计思想,那么关于深复制和浅复制也很容易理解。其实这里的深复制和浅复制也类似于cpp概念中的深浅复制。

    深复制和浅复制

    在上节[3]中提到复制,在python中一切都是对象,每个对象包含了idendity、type 和 value。所以python中的复制语句实际上是添加引用,将内存地址赋予了一个新的别名。

    浅复制

    浅复制一般出现在非嵌套的对象当中,python中的非容器对象(num,str,其他原子性对象),元组是个例外,后面会讲,对于复制都使用的是浅复制,不分浅复制和深复制。那么对于容器类对象,像list和dict,浅拷贝和深拷贝就有区分了。下面简单的例子:

    >>> import copy
    >>> b = [1, 2]
    >>> a = [b, 3, 4]
    >>> d = copy.copy(a)
    >>> print(id(d) is id(a))
    False
    >>> print(id(d[0]) is id(a[0]))
    True
    

    上述代码中d创建了一个a的浅复制,这时d会新创建一个对象,所以id(a) neq id(b),但是由于a是一个嵌套的容器对象,那么浅复制就不会复制内层内的b的对象,而是复制b的引用。所以id(d[0]) == id(a[0])。这时修改d[0]中的值同样会改变a[0]中的值。

    浅复制的几种情况:

    • 使用切片[:]操作
    • 使用工厂函数(如list/dir/set)
    • 使用copy模块中的copy()函数

    深复制

    深复制相对应与浅复制,浅复制是只有一层的对象复制,其他层都是引用。而深复制则是递归地进行复制,每一层都是对象复制。因此深复制会复制更多东西,占用更多内存,也比浅复制耗时。以下例子:

    >>> import copy
    >>> b = [1, 2]
    >>> a = [b, 3, 4]
    >>> d = copy.deepcopy(a)
    >>> print(id(d) is id(a))
    False
    >>> print(id(d[0]) is id(a[0]))
    False
    

    d会完全复制a中的所有内容,因此当d和a是两个完全不同的对象,由于递归复制了所有对象,那么显然d[0]和a[0]也是两个不同的对象,两者不相互影响。

    引发的问题

    python二维数组初始化

    如果使用list来初始化一个全0的数组,便很大可能出现问题,对于一维数组,可以简单地使用a = [0] * 3这里就是使用的浅复制。当二维数组时候就会:

    >>> a = [[0] * 3] *3
    >>> a[0][0] = 1
    >>> print(a)
    [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
    

    出现与感觉上相违背的事情,原因是这里的[]*n使用的时浅拷贝,当使用嵌套时,则出现这种错误,上述代码相当于:

    >>> b = [0] * 3
    >>> a = [b, b, b]
    

    正确的初始化方式为生成式[[0 for j in range(3)] for i in range(3)]或者使用nunpy。

    元组修改问题

    元组是不允许修改的,但是如果有以下写法,则是很容易出现问题。例子:

    a = ([1, 2], 3, 4)
    a[0] += [5, 6]
    print(a)
    

    当运行以上程序时,首先会报错:
    TypeError: 'tuple' object does not support item assignment,因为元组不允许被修改,但是当打印时会发现:a = ([1, 2, 5, 6], 3, 4),让人觉得很诡异,明明已经报错了,但是元组内的值还是被修改了。这其实因为是+=并不是一个原子操作,先执行的添加,然后再执行的赋值,当赋值时候添加完成了,但是赋值却不被允许。

    引用

    [1]. https://docs.python.org/3.6/library/copy.html
    [2]. http://wsfdl.com/python/2013/08/16/理解Python的深拷贝和浅拷贝.html
    [3]. https://www.cnblogs.com/wildkid1024/p/11093820.html

  • 相关阅读:
    Web应用Word生成
    记 Ubuntu14.04 Monodevelop 安装的两个问题
    CSDN上下载的一些关于Android程序调用Webservice执行不成功的问题
    Binary Search Tree Iterator
    算法之贪心算法
    《SAS编程与数据挖掘商业案例》学习笔记之十七
    数据库设计之半结构化存储
    Timus 1446. Sorting Hat 分类问题
    WebGL on iOS8 最终等到了这一天
    仿netty线程池简化版本
  • 原文地址:https://www.cnblogs.com/wildkid1024/p/11101350.html
Copyright © 2020-2023  润新知