Python 深浅拷贝 (Shallow copy and Deep copy in Python)

前言

昨天刷公众号看到一篇描述py优雅语法的文章,心痒之下到家就开始尝试,学习了for else statement,yield和py版三目写法。在列表切片这部分中,对作者的列表拷贝写法,有些不太理解。

# 拷贝
copy_items = items[::] 或者 items[:]

尝试

首先开一个python,随便建一个列表
l=[1,2,3]
将其进行两种方法的拷贝:

  1. 我的写法

    c=l
  2. 作者的写法

    d=l[:]

分别打印了cd,并没有什么差别,仔细斟酌了一下作者的用意,觉得应该有一些深层次的考虑。
于是使用id()分别查看两边的内存地址,这一打印出现了不同的结果。

>>> id(l)
39179656L
>>> id(c)
39179656L
>>> id(d)
39179272L

使用直接赋值的c的内存地址和原列表l的内存地址是一样的,而用切片方法拷贝的d的内存地址不一样。
我尝试改动l的值看一下结果。

>>> l.append(‘z‘)
>>> l
[1, 2, 3, ‘z‘]
>>> c
[1, 2, 3, ‘z‘]
>>> d
[1, 2, 3]

此时区别就显示出来了,使用直接赋值的c因为和原列表l指向同一个内存地址,所以当修改l的值的时候,打印c也发现同样的改变。

探索

稍微搜一下怎么拷贝一个列表,发现这个是有专有名词的,叫做 “深浅拷贝” (copy,deepcopy)。我原来直接赋值的写法只是将内存地址的引用传递到一个新的对象里,连浅拷贝都算不上。
Python的拷贝有一个专门的模块,叫做copy

浅拷贝

import copy;
>>> l=[1,2,3,[4,5],6]
>>> c=copy.copy(l)
>>> id(l)
39195912L
>>> id(c)
39238600L

从内存引用里清晰的显示,至少内存地址不一样了,对l进行内容变更应该不会影响到c

>>> l.append(‘z‘)
>>> l
[1, 2, 3, [4, 5], 6, ‘z‘]
>>> c
[1, 2, 3, [4, 5], 6]

但是毕竟是浅拷贝,只是拷贝了最外层对象,没有拷贝子对象。

>>> id(l[3])
39195784L
>>> id(c[3])
39195784L
>>> l[3].append(‘az‘)
>>> l
[1, 2, 3, [4, 5, ‘az‘], 6, ‘z‘]
>>> c
[1, 2, 3, [4, 5, ‘az‘], 6]

果然原列表l的子对象的内存地址和浅拷贝c的对应子对象的内存地址一样,所以当原列表的子对象内容发生改变时,也会影响到c

深拷贝

有了浅拷贝的经验,直接造一个深拷贝对象d,先查看一下外层对象和子对象的内存地址。

>>> l=[1,2,3,[4,5],6]
>>> d=copy.deepcopy(l)
>>> id(l)
39236296L
>>> id(d)
39195912L
>>> id(l[3])
39179656L
>>> id(d[3])
39236040L

结果清晰的显示,原列表l和深拷贝对象d对应外层对象和子对象的内存地址均不同。

>>> l.append(‘z‘)
>>> l
[1, 2, 3, [4, 5], 6, ‘z‘]
>>> d
[1, 2, 3, [4, 5], 6]
>>> l[3].append(‘az‘)
>>> l
[1, 2, 3, [4, 5, ‘az‘], 6, ‘z‘]
>>> d
[1, 2, 3, [4, 5], 6]

再查看一下结果,验证了我的猜想。

总结

Python是一门脚本语言,声明一个对象实际在内存中创建了一个地址存放对象,将对象名指向那个内存地址。用PHP的赋值方法进行赋值时,只是创建了一个新的对象名同时指向同一个内存地址。
py优雅语法的作者所用的列表拷贝方法c=l[:]用的就是浅拷贝,只是写法相对于copy.copy()更简洁。
通过Copy模块的代码可以发现deepcopy是在copy的基础上执行了递归。

# C:\Python27\Lib\copy.py
def deepcopy(x, memo=None, _nil=[]):
...
y = _reconstruct(x, rv, 1, memo);
...
def _reconstruct(x, info, deep, memo=None):
...
if deep:
args = deepcopy(args, memo);
...

备注:本文发布于2017-08-03,我github page的原文地址

时间: 2024-08-29 10:03:18

Python 深浅拷贝 (Shallow copy and Deep copy in Python)的相关文章

python中的shallow copy 与 deep copy

今天在写代码的时候遇到一个奇葩的问题,问题描述如下: 代码中声明了一个list,将list作为参数传入了function1()中,在function1()中对list进行了del()即删除了一个元素. 而function2()也把list作为参数传入使用,在调用完function1()之后再调用function2()就出现了问题,list中的值已经被改变了,就出现了bug. 直接上代码: list = [0, 1, 2, 3, 4, 5] def function1(list): del lis

Shallow copy and Deep copy

一.来自wikipidia的解释: Shallow copy One method of copying an object is the shallow copy. In that case a new object B is created, and the fields values of A are copied over to B. This is also known as a field-by-field copy,field-for-field copy, or field co

python 深浅拷贝 进阶

主要理解新与旧到底在哪里 这样也就理解了 深浅拷贝 先说说赋值,其实python中的赋值其实是赋值了一个引用,例如: foo1=1.0 foo2=foo1 用操作符is判断时,你可以发现结果是true,是因为python是先创建了一个对象1.0,然后这个对象的引用又被赋值给了foo1和foo2,但是如果是这样: foo1=1.0 foo2=1.0 这时你会发现,这其实是创建了两个不同的对象,用内建函数id()可以发现,二者的身份不同: 其实python还有一个特例,例如: a=1 b=1 你会发

8.6(数据类型分类,python深浅拷贝,异常处理,基本的文件操作,绝对路径和相对路径)

数据类型分类 按照存值个数: 存一个值:整型/浮点型/字符串 存多个值:列表/字典/元组/集合 按照有序和无序: 有序:字符串/列表/元组 无序:字典/集合 按照可变和不可变 可变:字典/列表/集合 不可变:整型/浮点型/字符串/元组 Python深浅拷贝 # 拷贝 赋值 # lt = [1,2,3] # lt2 = lt # lt.append(4) # print(lt) # print(lt2) # 列表为可变类型,所以lt的值变化,lt2的值也会跟着变化 # 浅拷贝 # import..

python深浅拷贝,集合以及数据类型的补充

1.基础数据类型的补充 1.元组 如果元组中只有一个数据,且没有逗号,则该'元组'与里面的数据的类型相同.如: 1 tu = (1) 2 tu1 = (1,) 3 tu2 = ('alex') 4 tu3 = ([1,2,3],) 5 print(tu,type(tu)) # 1 <class 'int'> 6 print(tu1,type(tu1)) # (1,) <class 'tuple'> 7 print(tu2,type(tu2)) # alex <class 's

Python开发【第二章】:Python深浅拷贝剖析

Python深浅拷贝剖析 Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 一.对象赋值 创建列表变量Alex,变量包含子列表,通过变量Alex给变量lzl赋值,对

NumPy学习(索引和切片,合并,分割,copy与deep copy)

NumPy学习(索引和切片,合并,分割,copy与deep copy) 目录 索引和切片 合并 分割 copy与deep copy 索引和切片 通过索引和切片可以访问以及修改数组元素的值 一维数组 程序示例 import numpy as np #索引与切片 array=np.arange(3,15) print(array) print(array[3])#数组下标为3的元素 print('\n') print(array[1:3])#取从下标1到下标3,不包括下标3 print(array[

copy&amp;mutableCopy 浅拷贝(shallow copy)深拷贝 (deep copy)

本文来自 这里,原文作者微博MicroCai 概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCop

Python深浅拷贝

深浅拷贝 深浅拷贝分为两部分,一部分是数字和字符串另一部分是列表.元组.字典等其他数据类型. 数字和字符串 对于数字和字符串而言,赋值.浅拷贝和深拷贝无意义,因为他们的值永远都会指向同一个内存地址. # 导入copy模块>>> import copy# 定义一个变量var1>>> var1 = 123# 输出var1的内存地址>>> id(var1)1347747440>>> var2 = var1# var2的内存地址和var1相同