• 深入理解Python中赋值、深拷贝(deepcopy)、浅拷贝(copy)


    赋值

    python跟java中的变量本质是不一样的,Python的变量实质上是一个指针(int型或str型),而java的变量是一个可操作的存储空间。

    a = 123
    b = a

    print(id(a))
    print(id(b))

    print(a is b)


    result:

      26848576
      26848576
      True

    这里可以看到a和b的地址是一样的,a=123,实质上是将a这个对象"贴到"123上;同样,b=a,也是将b这个对象“贴到”123上,这里变量实际上是个“便利贴“。

    下面用一个可变的对象list来做说明:

    a = [1, 2, 3]
    b = a
    
    a.append(4)
    a[0] = 6
    print(a)
    print(b)
    
    result:
    [6, 2, 3, 4]
    [6, 2, 3, 4]

    首先把a和b贴在 [1,2,3]这个对象上,然后通过append,[1,2,3]这个对象变成了[1,2,3,4],再通过a[0]=6,将对象[1,2,3,4]的第0个元素地址对应值改为6,

    则最终这个对象是[6,2,3,4],然而a和b仍然是贴在这个对象上的,即a和b都是[6,2,3,4]

    浅拷贝(copy)

    对于浅拷贝有两种情况:

    1. 浅拷贝值是不可变对象(数值,字符串,元组)时,等同于赋值,对象的id值与浅拷贝原来的值相同。

    import copy
    
    a = 1
    b = a
    c = copy.copy(a)
    
    print(id(a))
    print(id(b))
    print(id(c))
    
    result:
    35258712
    35258712
    35258712

    2. 浅拷贝值是可变对象(list,dict)时:

     2.1 不包含子对象

    # coding:utf-8
    import copy
    
    a = [1, 2, 3]
    b = a
    c = copy.copy(a)
    print("append前c={}".format(id(c)))
    a.append(4)
    
    print("a={}".format(id(a)))
    print("b={}".format(id(b)))
    print("append后c={}".format(id(c)))
    
    print("a值={}".format(a))
    print("b值={}".format(b))
    print("c值={}".format(c))
    
    
    result:
    append前c=139982846485352
    a=139982846912272
    b=139982846912272
    append后c=139982846485352
    a值=[1, 2, 3, 4]
    b值=[1, 2, 3, 4]
    c值=[1, 2, 3]

    对于不包含子对象的情况下,原值的改变并不会影响浅拷贝的值,同时浅复制的值改变也并不会影响原值,并且浅拷贝是新开辟的一块内存,与原对象内存地址不同。

     2.2 包含子对象

    # coding:utf-8
    import copy
    
    a = [1, [4], 2, 3]
    b = a
    c = copy.copy(a)
    print("append前c={}".format(id(c)))
    a.append(5)
    a[1].append(9)
    
    print("a={}".format(id(a)))
    print("b={}".format(id(b)))
    print("append后c={}".format(id(c)))
    
    print("a值={}".format(a))
    print("b值={}".format(b))
    print("c值={}".format(c))
    
    
    result:
    append前c=140519703466856
    a=140519703889752
    b=140519703889752
    append后c=140519703466856
    a值=[1, [4, 9], 2, 3, 5]
    b值=[1, [4, 9], 2, 3, 5]
    c值=[1, [4, 9], 2, 3]

     可以看出,浅拷贝只拷贝父对象([1,2,3]),不会拷贝对象内部的子对象([4]),改变原对象中复杂子对象的值时会改变浅拷贝的值。

    深拷贝(deepcopy)

    # coding:utf-8
    import copy
    
    a = [1, [4], 2, 3]
    print("a原始值={}".format(a))
    b = a
    d = copy.deepcopy(a)
    
    a.append(5)
    a[1].append(9)
    
    print("a={}".format(id(a)))
    print("b={}".format(id(b)))
    print("d={}".format(id(d)))
    
    print("a值={}".format(a))
    print("b值={}".format(b))
    print("d值={}".format(d))
    
    
    result:
    a原始值=[1, [4], 2, 3]
    a=139675956164440
    b=139675956164440
    d=139675955741904
    a值=[1, [4, 9], 2, 3, 5]
    b值=[1, [4, 9], 2, 3, 5]
    d值=[1, [4], 2, 3]

    深拷贝则会拷贝对象及其子对象,深拷贝的时候会将复杂对象的每一层复制一个单独的个体出来,原对象的值改变时并不会影响deepcopy的值,

    但是,由于深拷贝需要维护一个 内存 用于记录已经拷贝的对象,所以深拷贝的速度会比较慢。

  • 相关阅读:
    SqlServer注意事项总结,高级程序员必背!
    C#语法——委托,架构的血液
    C#语法——泛型的多种应用
    C#——Nhibernate探索
    C#语法——await与async的正确打开方式
    谈谈我理解的SA——Systems Architecture
    C#线程安全使用(五)
    C#语法——元组类型
    架构师的御人之道
    另一个角度的架构师
  • 原文地址:https://www.cnblogs.com/FG123/p/9463390.html
Copyright © 2020-2023  润新知