zoukankan      html  css  js  c++  java
  • 深浅copy

    铺垫(深入理解内存地址)

    学习深浅copy之前,我们先来看一个例子

    1 l1 = [1, 2, 3]
    2 l2 = l1
    3 l2.append(4)
    4 print(l1, l2)

    猜猜结果是怎样的?l1是打印[1,2,3]还是[1,2,3,4],来看结果

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

    看到没,l2添加了一个元素4后l1也跟着改变,这说明l1,l2指向的是同一个内存地址,我们可以用is验证一下

    print(l1 is l2)

    执行结果

    True

    说明l1和l2的指向同一个内存地址,l1,l2的内存地址相同,那么它们的元素的内存地址是否相同呢,来看

    print(id(l1[0]), id(l2[0]))

    执行结果

    1445227552 1445227552

    元素的内存地址也相同,列表里的元素不仅仅是数字,也可以是列表或者字典等可变数据类型,那么对于这些可变数据类型,它们的内存地址是否相同呢,来看代码

    1 l1 = [1, 2, [3, 4, 5]]
    2 l2 = l1
    3 print(id(l1), id(l2))
    4 print(id(l1[1]), id(l2[1]))
    5 print(id(l1[-1]), id(l2[-1]))

    执行结果

    1950802883592 1950802883592
    1445227584 1445227584
    1950802883656 1950802883656

    可见对于可变数据类型,内存地址也是相同的。因此我们可以得出结论,对于赋值运算,是将原对象的内存地址赋值给新对象,等号两边的对象的内存地址和元素的内存地址都是完全相同的。

    浅copy

    浅copy是利用列表或字典的copy方法来复制,其内部机制是怎样的呢,来看一段代码

     1 l1 = [1, "abc", [1, 2]]
     2 l2 = l1.copy()
     3 print(id(l1), id(l2))   # 内存地址不同
     4 print(id(l1[0]), id(l2[0]))
     5 print(id(l1[-1]), id(l2[-1]))    # 内存地址相同
     6 l1.append(3)
     7 print("l1   ", l1)
     8 print("l2   ", l2)     # l2没有加上3
     9 l1[-2].append(3)
    10 print("l1   ", l1)
    11 print("l1   ", l2)

    执行结果

    1156212831240 1156212831432
    1445227552 1445227552
    1156212831304 1156212831304
    l1 [1, 'abc', [1, 2], 3]
    l2 [1, 'abc', [1, 2]]
    l1 [1, 'abc', [1, 2, 3], 3]
    l1 [1, 'abc', [1, 2, 3]]

    再来看看字典

     1 dic1 = {1: "a", 2: "b", 3: [1, 2, 3]}
     2 dic2 = dic1.copy()
     3 print(id(dic1), id(dic2))
     4 print(id(dic1[1]), id(dic2[1]))
     5 print(id(dic1[3]), id(dic2[3]))
     6 dic1[4] = "m"
     7 print(dic1)
     8 print(dic2)
     9 dic1[3].append(4)
    10 print(dic1)
    11 print(dic2)

    执行结果

    2260199788616 2260199788688
    2260199617232 2260199617232
    2260229796936 2260229796936
    {1: 'a', 2: 'b', 3: [1, 2, 3], 4: 'm'}
    {1: 'a', 2: 'b', 3: [1, 2, 3]}
    {1: 'a', 2: 'b', 3: [1, 2, 3, 4], 4: 'm'}
    {1: 'a', 2: 'b', 3: [1, 2, 3, 4]}

    可以看出,浅copy的机制是:

    1. 新开辟一个内存地址(新的容器)

    2. 把原列表(或字典)的对应元素的内存地址放入新列表(字典)里面

    也就是说创建了一个新的容器,但是里面的内容跟原容器是一样的,原容器的原内容(不包括新添加的)发生改变,新容器的对应内容也会发生改变。

    浅copy不仅可以通过copy方法,还可以通过列表的切片

    1 l1 = [1, "abc", [1, 2]]
    2 l2 = l1[:]
    3 print(id(l1), id(l2))    # id不一样

    执行结果

    2183077803016 2183077803208

    因此列表的切片(全切)是浅copy

    深copy

    深copy可以利用copy模块里的deepcopy方法

    1 import copy
    2 l1 = [1, "abc", [1, 2]]
    3 l2 = copy.deepcopy(l1)
    4 print(id(l1), id(l2))
    5 print(id(l1[0]), id(l2[0]))      # 内存地址相同(不可变数据类型)
    6 print(id(l1[1]), id(l2[1]))      # 内存地址相同
    7 print(id(l1[-1]), id(l2[-1]))    # 内存地址不同(可变数据类型)

    执行结果

    2267524916744 2267524918024
    1445227552 1445227552
    2267522383976 2267522383976
    2267524916552 2267524917960

    由此我们可以总结深copy的原理:

    1. 新开辟一个内存地址(新的容器)

    2. 对于不可变元素,沿用之前的(内存地址相同)

    3. 对于可变元素,重新创建一份(内存地址不同)

  • 相关阅读:
    C#下IOC/依赖注入框架Grace介绍
    关于C#的new与override
    关于SQL中SELECT *(星号)的危害论
    WCF优雅使用 KnownType标记的方法
    SQL常用语句整理
    html5中的一些小知识点(CSS)
    MyEclipse导入Maven项目报错 Plugin execution not covered by lifecycle configuration:
    sql查询每门课程成绩最高的学生
    javascript 写一段代码,判断一个字符串中出现次数最多的字符串,并统计出现的次数
    Uncaught TypeError: Cannot set property 'innerHTML' of null
  • 原文地址:https://www.cnblogs.com/zzliu/p/10192785.html
Copyright © 2011-2022 走看看