Python 深浅拷贝

时间:2022-05-06
本文章向大家介绍Python 深浅拷贝,主要内容包括Python浅拷贝和深度拷贝、浅拷贝、深拷贝、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

Python浅拷贝和深度拷贝

今天面试了一个计算机专业研究生且大学出身也很好,但是面试的结果来看并没有达到我的预期。很多基础计算机的知识貌似都不是很懂,更别说对操作系统、编译原理和算法的深度造化了。不排除高级语言和IDE隐藏了很多细节,但是当你去追求更高性能或者你想进阶的话,我想说底层的东西真的很重要。只有你完全掌握这些底层的东西,你才能通过高级语言特性来优化你的业务和应用。虽然有点扯淡,还是开始咱们今天聊一下Python的浅拷贝和深度拷贝。

对象赋值

在Python中大致可以分为immutable和mutable两种数据类型,比如:字符串字面值、数字、元组等这些是immutable类型,列表、字典等是mutable类型。我们先来看一下python对象赋值是如何赋值的?

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from copy import copy,deepcopy

adr = lambda x:hex(id(x))    

def test(count=None):
    print"test method before id ",adr(count)
    if type(count)==list:
        count.append(1)
    else:
        count+=1
    print"test method after id ",adr(count)


if __name__ == "__main__":
    a,b = 1,1
    c,d = [],[]
    print"a,b,c,d id ",map(adr,(a,b,c,d))
    print"1,1,[],[] id ",map(adr,(1,1,[],[]))
    print"c=",c
    test(c)
    print"c=",c
    print"a=",a
    test(a)
    print"a=",a
运行结果如下所示:
a,b,c,d id  ['0x10030c0b8', '0x10030c0b8', '0x10269c488', '0x1006ea200']
1,1,[],[] id  ['0x10030c0b8', '0x10030c0b8', '0x102693320', '0x10269ec68']
c= []
test method before id  0x10269c488
test method after id  0x10269c488
c= [1]
a= 1
test method before id  0x10030c0b8
test method after id  0x10030c0a0
a= 1

我们先分析一下我们所写的代码,我们新建了四个变量分别为a,b,c和d。其中都为相同的字面值或者说都是相同的object,在python一切皆对象。我们看到immutable类型是赋值操作是直接传递内存地址;而对于mutable类型,赋值操作定义一个新的对象,将右值对象内存地址传递给这个新的对象。函数参数传递是按照内存地址传递,其引用传递。

浅拷贝

我们先看一下Demmo:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from copy import copy,deepcopy

adr = lambda x:hex(id(x))    

if __name__ == "__main__":
    p = ['brian',25,["python"]]
    p1 = copy(p)
    print"p id,p1 id",map(adr,(p,p1))
    print"p element id==",map(adr,p)
    print"p1 element id==",map(adr,p1)
    print".....change ......"
    p[0]="lv"
    p[1]=1111
    p[2].append(12)
    print"p element id==",map(adr,p)
    print"p1 element id==",map(adr,p1)
运行结果如下所示:
p id,p1 id ['0x10399e320', '0x103ac5950']
p element id== ['0x103aae990', '0x10030be78', '0x1006ea200']
p1 element id== ['0x103aae990', '0x10030be78', '0x1006ea200']
.....change ......
p element id== ['0x1021bbd78', '0x102068218', '0x1006ea200']
p1 element id== ['0x103aae990', '0x10030be78', '0x1006ea200']

非常清晰的可以看到,浅拷贝对于immutable类型来说是拷贝了一个不可变的对象的引用, 修改你得到的变量只会让该变量的引用指向一个新的对象,而对于mutable类型来说还是对象引用。使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用. 看一下产生浅拷贝的效果操作:

  • 使用切片[:]操作
  • 使用工厂函数(如list/dir/set)
  • 使用copy模块中的copy()函数

深拷贝

深拷贝是完全真正意义上的拷贝,是完全复制所有对象元素。但是对于原子类型对象(immutable)是没有深拷贝这么一说的。先来看一下例子:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from copy import copy,deepcopy

adr = lambda x:hex(id(x))    

if __name__ == "__main__":
    p = ['brian',25,["python"]]
    p1 = deepcopy(p)
    print"p id,p1 id",map(adr,(p,p1))
    print"p element id==",map(adr,p)
    print"p1 element id==",map(adr,p1)
    print".....change ......"
    p[0]="lv"
    p[1]=1111
    p[2].append(12)
    print"p element id==",map(adr,p)
    print"p1 element id==",map(adr,p1)
运行结果如下:
p id,p1 id ['0x101e93320', '0x101e9eef0']
p element id== ['0x101fab990', '0x10030be78', '0x1006ea200']
p1 element id== ['0x101fab990', '0x10030be78', '0x101e9cf38']
.....change ......
p element id== ['0x1019bbd78', '0x100733f48', '0x1006ea200']
p1 element id== ['0x101fab990', '0x10030be78', '0x101e9cf38']

deepcopy是完全意义上的copy,实现了真正的隔离。