zoukankan      html  css  js  c++  java
  • python深浅拷贝的深度解析(内存/地址)

    前置知识

    1.python没有指针, 可以通过内置函数id来查看内存地址
    2.python中list存放的是地址, 而非元素本身, 地址是按顺序存放的
    3.python容器类型list有两种地址, 一个是外层对象/父对象地址, 一个是每个元素/子对象的地址
    4.当修改list中的不可变对象时, 对象会发生拷贝copy-on-write, list存放的地址会发生变化, 这点可以保证任何拷贝都无需拷贝不可变对象本身, 只需要拷贝地址即可

    import copy
    a = [1, 2, [3, 4]]
    b = a
    c = a.copy()
    d = copy.deepcopy(a)
    
    # 测试
    assert id(a) == id(b) and id(a[0]) == id(b[0]) and id(a[2]) == id(b[2])
    assert id(a) != id(c) and id(a[0]) == id(c[0]) and id(a[2]) == id(c[2])
    assert id(a) != id(d) and id(a[0]) == id(d[0]) and id(a[2]) != id(d[2])
    
    a[0] = 5
    
    assert id(a) == id(b) and id(a[0]) == id(b[0]) and id(a[2]) == id(b[2])
    assert id(a) != id(c) and id(a[0]) != id(c[0]) and id(a[2]) == id(c[2])
    assert id(a) != id(d) and id(a[0]) != id(d[0]) and id(a[2]) != id(d[2])
    
    a[2].append(6)
    
    assert id(a) == id(b) and id(a[0]) == id(b[0]) and id(a[2]) == id(b[2])
    assert id(a) != id(c) and id(a[0]) != id(c[0]) and id(a[2]) == id(c[2])
    assert id(a) != id(d) and id(a[0]) != id(d[0]) and id(a[2]) != id(d[2])
    

    这三种"拷贝"方式有各自的含义
    1.b = a
    b是a的一个引用, 不存在任何对象和地址拷贝, 即b只是a的一个别名
    2.c = a.copy()
    c拷贝了a的外层对象, 内层对象的地址
    当a中的不可变对象发生变化, a中的地址变化(参照前置知识4), c中的地址不变, 体现为c中的元素不跟随a变化
    当a中的可变对象发生变化, a中的地址不变, c中的地址不变, 体现为c中的元素跟随a变化
    3.d = copy.deepcopy(a)
    d拷贝了a的外层对象, 内层可变对象, 内层不可变对象的地址(参照前置知识4), 与a完全独立,

    总结: 深浅拷贝的区别在于拷贝的是内层可变对象的地址还是内层可变对象本身(对于不可变对象来说, 永远只需要拷贝地址)

    如有疏忽错误,
    欢迎批评指正!

  • 相关阅读:
    异常处理
    添加headers头文件反爬虫
    爬百思不得姐的视频(爬多页时for的循环)
    图片爬取百思不得姐(正则的取法,下载的方法,%s的用法)
    创建一个网页
    集合幂级数总结
    题解(新)
    JOI汉堡肉
    NOIO 2020 r2 总结
    长链剖分
  • 原文地址:https://www.cnblogs.com/chendongblog/p/14084949.html
Copyright © 2011-2022 走看看