zoukankan      html  css  js  c++  java
  • python浅拷贝和深拷贝

    【自己总结】:浅拷贝和深拷贝都是针对容器类型而言的。
        如果此容器的元素都是‘原子’类型的,那么shallow copy 和 deep copy没什么区别,
        如果此容器的元素不都是‘原子’类型的,则区别在于此容器中非‘原子’的元素。所有的浅拷贝中此非原子元素的身份是一样的,也都和原始的元素身份一样,所以如果改变此元素的一个元素,其他拷贝都会变化
        而深拷贝则此非原子元素的身份和 原始元素以及浅拷贝元素 的身份不同,是完全独立的。
        另外注意,对于浅拷贝和深拷贝所针对的容器(最外层容器),新的拷贝无论是浅的还是深的,此容器的身份都和原始不同,彼此也不同。

    【测试例子】

    person = ['name', ['savings', 100]]
    hubby = person[:] # 完全切片操作,和直接 hubby = person不一样
    wifey = list(person)
    print([id(x) for x in (person, hubby, wifey)])
    print([id(x) for x in person])
    print([id(x) for x in hubby])
    print([id(x) for x in wifey])

    print([id(x) for x in person[1]])
    print([id(x) for x in hubby[1]])
    print([id(x) for x in wifey[1]])
    hubby[0] = 'John'
    wifey[0] = 'Jane'
    print(hubby, wifey)
    hubby[1][1] = 50
    print(hubby, wifey)
    print([id(x) for x in (person, hubby, wifey)])
    print([id(x) for x in person])
    print([id(x) for x in hubby])
    print([id(x) for x in wifey])

    print([id(x) for x in person[1]])
    print([id(x) for x in hubby[1]])
    print([id(x) for x in wifey[1]])

    运行结果如下,

    [140244615059936, 140244615059504, 140244614511216]
    [140244651551352, 140244615058784]
    [140244651551352, 140244615058784]
    [140244651551352, 140244615058784]
    [140244614947872, 9356480]
    [140244614947872, 9356480]
    [140244614947872, 9356480]
    ['John', ['savings', 100]] ['Jane', ['savings', 100]]
    ['John', ['savings', 50]] ['Jane', ['savings', 50]]
    [140244615059936, 140244615059504, 140244614511216]
    [140244651551352, 140244615058784]
    [140244614948432, 140244615058784]
    [140244614948488, 140244615058784]
    [140244614947872, 9354880]
    [140244614947872, 9354880]
    [140244614947872, 9354880]

    当丈夫取走$50后,他的行为影响到了他妻子的账户,为什么会这样呢?

    原因是我们仅仅做了一个浅拷贝。对一个对象进行浅拷贝其实是新创建了一个类型跟原对
    象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不
    是.序列类型对象的浅拷贝是默认类型拷贝,并可以以下几种方式实施:(1)完全切片操作[:],(2)
    利用工厂函数,比如 list(),dict()等,(3)使用 copy 模块的 copy 函数.
    你的下一个问题可能是:当妻子的名字被赋值,为什么丈夫的名字没有受到影响?难道它们
    的名字现在不应该都是'jane'了吗?为什么名字没有变成一样的呢?怎么会是这样呢?这是因为
    在这两个列表的两个对象中,第一个对象是不可变的(是个字符串类型),而第二个是可变的(一
    个列表).正因为如此,当进行浅拷贝时,字符串被显式的拷贝,并新创建了一个字符串对象,而列
    表元素只是把它的引用复制了一下,并不是它的成员.所以改变名字没有任何问题,但是更改他
    们银行账号的任何信息都会引发问题.现在,让我们分别看一下每个列表的元素的对象 ID 值,注
    意,银行账号对象是同一个对象,这也是为什么对一个对象进行修改会影响到另一个的原因

    
    

    假设我们要给这对夫妻创建一个联合账户,那这是一个非常棒的方案,但是,如果需要的是
    两个分离账户,就需要作些改动了.要得到一个完全拷贝或者说深拷贝--创建一个新的容器对象,
    包含原有对象元素(引用)全新拷贝的引用--需要 copy.deepcopy()函数.我们使用深拷贝来重
    写整个例子.
    >>> person = ['name', ['savings', 100.00]]
    >>> hubby = person
    >>> import copy
    >>> wifey = copy.deepcopy(person)
    >>> [id(x) for x in person, hubby, wifey]
    [12242056, 12242056, 12224232]
    >>> hubby[0] = 'joe'
    >>> wifey[0] = 'jane'
    >>> hubby, wifey
    (['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])
    >>> hubby[1][1] = 50.00
    >>> hubby, wifey
    (['joe', ['savings', 50.0]], ['jane', ['savings', 100.0]])
    这就是我们想要的方式,作为验证,让我们确认一下所有四个对象都是不同的.
    >>> [id(x) for x in hubby]
    [12191712, 11826280]

    >>> [id(x) for x in wifey]
    [12114080, 12224792]
    以下有几点关于拷贝操作的警告。
    第一,非容器类型(比如数字,字符串和其他"原子"类型的
    对象,像代码,类型和 xrange 对象等)没有被拷贝一说,浅拷贝是用完全切片操作来完成的.第二,
    如果元组变量只包含原子类型对象,对它的深拷贝将不会进行.如果我们把账户信息改成元组类
    型,那么即便按我们的要求使用深拷贝操作也只能得到一个浅拷贝:
    >>> person = ['name', ('savings', 100.00)]
    >>> newPerson = copy.deepcopy(person)
    >>> [id(x) for x in person, newPerson]
    [12225352, 12226112]
    >>> [id(x) for x in person]
    [9919616, 11800088]
    >>> [id(x) for x in newPerson]
    [9919616, 11800088]
    核心模块: copy
    我们刚才描述的浅拷贝和深拷贝操作都可以在 copy 模块中找到.其实 copy 模块中只有两
    个函数可用:copy()进行浅拷贝操作,而 deepcopy()进行深拷贝操作.

    附,自己测深拷贝:

    # 深拷贝
    import copy
    person = ['name', ['savings', 100]]
    hubby = person[:]
    wifey = copy.deepcopy(person)
    print(person, hubby, wifey)
    print([id(x) for x in (person, hubby, wifey)])
    print([id(x) for x in person])
    print([id(x) for x in hubby])
    print([id(x) for x in wifey])

    print([id(x) for x in person[1]])
    print([id(x) for x in hubby[1]])
    print([id(x) for x in wifey[1]])
    hubby[0] = "john"
    wifey[0] = "jane"
    hubby[1][1] = 50
    print(person, hubby, wifey)
    print([id(x) for x in (person, hubby, wifey)])
    print([id(x) for x in person])
    print([id(x) for x in hubby])
    print([id(x) for x in wifey])

    print([id(x) for x in person[1]])
    print([id(x) for x in hubby[1]])
    print([id(x) for x in wifey[1]])

    ['name', ['savings', 100]] ['name', ['savings', 100]] ['name', ['savings', 100]]
    [140043683903536, 140043683903896, 140043683882048]
    [140043720383096, 140043683881688]
    [140043720383096, 140043683881688]
    [140043720383096, 140043683890096]
    [140043683779616, 9356480]
    [140043683779616, 9356480]
    [140043683779616, 9356480]
    ['name', ['savings', 50]] ['john', ['savings', 50]] ['jane', ['savings', 100]]
    [140043683903536, 140043683903896, 140043683882048]
    [140043720383096, 140043683881688]
    [140043683780176, 140043683881688]
    [140043683780232, 140043683890096]
    [140043683779616, 9354880]
    [140043683779616, 9354880]
    [140043683779616, 9356480]

  • 相关阅读:
    Leetcode刷题记录--39. 组合总和
    Leetcode刷题记录--31. 下一个排列
    Leetcode刷题记录--22. 括号生成(回溯)
    Leetcode刷题记录--17. 电话号码的字母组合(回溯)
    分布式学习之--6.824MITLab1记录
    总结javascript处理异步的方法
    引用、浅拷贝及深拷贝 到 Map、Set(含对象assign、freeze方法、WeakMap、WeakSet及数组map、reduce等等方法)
    Vue之富文本tinymce爬坑录
    iOS 13 正式发布,来看看有哪些 API 变动
    Vuex,从入门到...
  • 原文地址:https://www.cnblogs.com/everest33Tong/p/6567743.html
Copyright © 2011-2022 走看看