• Python深拷贝和浅拷贝


    1- Python引用计数[1]

      1.1 引用计数机制

        引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。使用引用计数技术可以实现自动资源管理的目的。同时引用计数还可以指使用引用计数技术回收未使用资源的垃圾回收算法。

        当创建一个对象的实例并在堆上申请内存时,对象的引用计数就为1,在其他对象中需要持有这个对象时,就需要把该对象的引用计数加1,需要释放一个对象时,就将该对象的引用计数减1,直至对象的引用计数为0,对象的内存会被立刻释放。

      1.2 垃圾回收

        当对象的引用计数为0,对象的内存会被立刻释放,称为垃圾回收

      1.3 引用计数增加情况

        (1). 对象被创建:x=4

        (2). 另外的别人被创建:y=x

        (3). 被作为参数传递给函数:foo(x)

        (4). 作为容器对象的一个元素:a=[1,x,'33']

      1.4 引用计数减少情况

        (1). 一个本地引用离开了它的作用域。比如上面的foo(x)函数结束时,x指向的对象引用减1。

        (2). 对象的别名被显式的销毁:del x ;或者del y

        (3). 对象的一个别名被赋值给其他对象:x=789

        (4). 对象从一个窗口对象中移除:myList.remove(x)

        (5). 窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。


     2- 深浅拷贝[2,3]

      2.1 赋值    

        其实python中的赋值其实是使引用计数+1,例如:

    foo1 = 1.0
    foo2 = foo1
    foo1 is foo2   #True
    id(foo1) = 18719720
    id(foo2) = 18719720

        但是如果是这样:

    foo1=1.0
    foo2=1.0
    foo1 is foo2    #False
    id(foo1) = 18719888
    id(foo2) = 18719840

        这时你会发现,这其实是创建了两个不同的对象,用内建函数id()可以发现,二者的身份不同。

        其实python还有一个特例,例如:

    a = 1
    b = 1
    id(a) = 14332248
    id(b) = 14332248
    

        原因是python认为这些小整型是会经常用到的,所以python会缓存一部分小整型。

        

      2.2 深拷贝 & 浅拷贝

        序列类型的可以通过三种方式实现浅拷贝,浅拷贝也是默认的拷贝类型:(1)完全切片操作;(2)利用工厂函数,比如list()等;(3)使用copy模块中的copy()函数。

        在《Python核心编程》一书中说道,“对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不是”。

    import copy
    a = [1, 2, 3, 4, ['a', 'b', 'c']]
    b = a
    c = copy.copy(a)
    
    id(a)       #139879301469392
    id(b)       #139879301469392        
    id(c)       #139879298646816, 可以看出所谓的“拷贝对象本身是新的“
    
    [id(x) for x in a]        #[14332248, 14332224, 14332200, 14332176, 139879298781912]
    [id(x) for x in b]        #[14332248, 14332224, 14332200, 14332176, 139879298781912]
    [id(x) for x in c]        #[14332248, 14332224, 14332200, 14332176, 139879298781912], 即”内容是旧的“
    

      最后,深拷贝和浅拷贝的区别^_^

    import copy
    a = [1, 2, 3, 4, ['a', 'b', 'c']]
    c = copy.copy(a)
    d = copy.deepcopy(a)
    
    id(a)       #139879301469392  
    id(c)       #139879298646816
    id(d)       #139879301462784
    
    [id(x) for x in a]        #[14332248, 14332224, 14332200, 14332176, 139879298781912]
    [id(x) for x in c]        #[14332248, 14332224, 14332200, 14332176, 139879298781912]
    [id(x) for x in d]        #[14332248, 14332224, 14332200, 14332176, 139879302072512]
    
    ##################################
    a.append(5)
    a[4].append('hello')
    
    a        #[1, 2, 3, 4, ['a', 'b', 'c', 'hello'], 5]
    c        #[1, 2, 3, 4, ['a', 'b', 'c', 'hello']]
    d        #[1, 2, 3, 4, ['a', 'b', 'c']]
    
    [id(x) for x in a]        #[14332248, 14332224, 14332200, 14332176, 139879298781912, 14332152]
    [id(x) for x in c]        #[14332248, 14332224, 14332200, 14332176, 139879298781912]
    [id(x) for x in d]        #[14332248, 14332224, 14332200, 14332176, 139879302072512]
    
    #################################
    a[1] = 0
    c[2] = 0
    d[3] = 0
    
    a        #[1, 0, 3, 4, ['a', 'b', 'c', 'hello'], 5]
    c        #[1, 2, 0, 4, ['a', 'b', 'c', 'hello']]
    d        #[1, 2, 3, 0, ['a', 'b', 'c']]
    
    [id(x) for x in a]        #[14332248, 14332272, 14332200, 14332176, 139879298781912, 14332152]  a[1]关联到新对象
    
    [id(x) for x in c]        #[14332248, 14332224, 14332272, 14332176, 139879298781912]  c[2]关联到新对象
    
    [id(x) for x in d]        #[14332248, 14332224, 14332200, 14332272, 139879302072512]  d[3]关联到新对象
    ################################
    # 1
    del a[0]
    a        #[   0, 3, 4, ['a', 'b', 'c', 'hello'], 5]
    c        #[1, 2, 0, 4, ['a', 'b', 'c', 'hello']]
    d        #[1, 2, 3, 0, ['a', 'b', 'c']]
    
    del c[0]
    a        #[   0, 3, 4, ['a', 'b', 'c', 'hello'], 5]
    c        #[   2, 0, 4, ['a', 'b', 'c', 'hello']]
    d        #[1, 2, 3, 0, ['a', 'b', 'c']]
    
    del d[0]
    a        #[   0, 3, 4, ['a', 'b', 'c', 'hello'], 5]
    c        #[   2, 0, 4, ['a', 'b', 'c', 'hello']]
    d        #[   2, 3, 0, ['a', 'b', 'c']]
    
    # 2
    del a[3][0]
    a        #[   0, 3, 4, [     'b', 'c', 'hello'], 5]
    c        #[   2, 0, 4, [     'b', 'c', 'hello']]
    d        #[   2, 3, 0, ['a', 'b', 'c']]

    简单点说

      1. copy.copy 浅拷贝     -拷贝一个对象,但是对象的属性还是引用原来的。拷贝了一个不可变的对象的引用, 修改你得到的变量只会让该变量的引用指向一个新的对象(如a或c中数值元素改变不会影响另一个)

                   可以这样记忆,浅拷贝的各个元素整体上改变是没有影响的,但仅元素部分修改是互相牵制的

    a = [1, 2, ['a', 'b'], ['c', 'd']]
    b = copy.copy(a)
    
    #整体
    a[0] = 0
    a    #[0, 2, ['a', 'b'], ['c', 'd']]
    b    #[1, 2, ['a', 'b'], ['c', 'd']]
    
    del a[3]
    a    #[0, 2, ['a', 'b']]
    a    #[1, 2, ['a', 'b'], ['c', 'd']]
    
    #局部
    a[2].append('haha')
    a    #[0, 2, ['a', 'b', 'haha']]
    a    #[1, 2, ['a', 'b', 'haha'], ['c', 'd']]


      2. copy.deepcopy 深拷贝  -拷贝一个对象,把对象里面的属性也做了拷贝,deepcopy之后完全是另一个对象了,实现完全独立

    #打印['a','b','c']地址
    [id(x) for x in a[3]]    #[1398793470232, 139879343471752, 139879314380720]
    [id(x) for x in c[3]]    #[1398793470232, 139879343471752, 139879314380720]
    [id(x) for x in d[3]]    #[1398793470192, 139879343470232, 139879343471752]

    [1] Python是如何进行内存管理的?

    [2] Python的赋值、浅拷贝和深拷贝

    [3] 从Python中copy与deepcopy的区别看Python引用

  • 相关阅读:
    HTTP协议强化理解
    常识
    向后看,比起实习期,现在的你不是已经很好了吗?
    Git学习笔记——一个NB的分布式版本控制系统
    计算机通识
    多测师讲解——sql 注入——高级讲师肖sir
    多测师讲RF _关键字整理_高级讲师肖sir
    多测师讲解RF _REQUEST_高级讲师肖sir
    多测师jenkins_svn和git拉取代码_高级讲师肖sir
    多测师讲解jenkins_设置邮箱_高级讲师肖sir
  • 原文地址:https://www.cnblogs.com/freyr/p/4410281.html
Copyright © 2020-2023  润新知