hijack 发表于 2017-6-14 19:26

说说python下的赋值,深拷贝与浅拷贝

本帖最后由 hijack 于 2017-6-14 19:28 编辑

初学python的朋友一定会遇到过这个问题:n1=123
n2=n1
n1=456
n2=?
今天就针对这个问题详细说一说赋值,深拷贝与浅拷贝
python的深拷贝浅拷贝需要分两方面来说:字符串与数字类型;其他数据类型
首先看看字符串与数字类型:
对于字符串与数字类型:赋值,深拷贝,浅拷贝都是一回事儿,不用区别import copy
# 数字、字符串
n1 = 123
print(id(n1)) #id方法的返回值就是对象的内存地址

​n2 = n1 #这是赋值
print(id(n2))

n3 = copy.copy(n1) #这是浅拷贝
print(id(n3))   

n4 = copy.deepcopy(n1) #这是深拷贝
print(id(n3))
我们来查看下n1,n2,n3,n4的内存地址,如下图



对于字符串和数字来说,都一样,都是返回同一个内存地址,我们再来看看其他数据类型:
1、赋值,就是再创建个变量,指向原来内存地址n1 = {"k1": "hi", "k2": 123, "k3": ["hijack", 678]}
n2 = n1
此时的id(n1)=id(n2)和上面字符串一样

2、浅拷贝
浅拷贝,顾名思义,很浅呐,那么就是只是在内存中只额外创建第一层数据import copy
n1 = {"k1": "hi", "k2": 123, "k3": ["hijack", 678]}
n2 = copy.copy(n1)
print(id(n1),id(n2))
我们来看看内存地址

和赋值不同,浅拷贝的内存地址并不相同,看看图解释下


看看,是不是很浅,只创建第一层
3、深拷贝
深拷贝,顾名思义,很深呐,深到什么程度?深到除了最后一层,其余都重新创建一份(python内部对字符串和数字的优化)import copy
n1 = {"k1": "hi", "k2": 123, "k3": ["hijack", 678]}
n2 = copy.deepcopy(n1)
print(id(n1),id(n2))
同样n1和n2指向的内存地址肯定不一样,看看画图解释:


以上就是一些关于赋值,深拷贝浅拷贝的知识了,说的有什么不周到的还请多多指正
如果觉得觉得这篇文章对你有一点点作用的话,还请给个免费评分

rexyan 发表于 2017-6-20 21:32

楼主说得已经很好了。下面,我自己补充点吧!

1,浅拷贝,没有拷贝到子对象。所以原始数据改变,没有被拷贝到的子对象会改变
i1={'k3': ['hijack', 678], 'k2': 123, 'k1': 'hi'}
import copy
i2=copy.copy(i1)
i3=copy.deepcopy(i1)

现在改变原数据(最外层的),因为深拷贝和浅拷贝都涉及到了这一层,所以这一层的数据改变,不会影响拷贝的内容
>>> i1["k4"]="add_data_test"
>>> i2
{'k3': ['hijack', 678], 'k2': 123, 'k1': 'hi'}
>>> i3
{'k3': ['hijack', 678], 'k2': 123, 'k1': 'hi'}
>>> i1
{'k3': ['hijack', 678], 'k2': 123, 'k1': 'hi', 'k4': 'add_data_test'}

现在改变原数据(最内层的),因为深拷贝没有涉及到这一层,所以浅拷贝的结果会受到影响,而深拷贝的话,里面的对象也是被拷贝了的,所以值不会被改变
>>> i1["k3"].append("k3_test")
>>> i1
{'k3': ['hijack', 678, 'k3_test'], 'k2': 123, 'k1': 'hi', 'k4': 'add_data_test'}
>>> i2
{'k3': ['hijack', 678, 'k3_test'], 'k2': 123, 'k1': 'hi'}
>>> i3
{'k3': ['hijack', 678], 'k2': 123, 'k1': 'hi'}
>>>

总结:copy.copy()这个方法得到的对象是新对象,但是数据还是引用。
如果要完全得到一个新的一模一样的对象,要用copy.deepcopy()方法。这样,在改变新对象的时候,原对象才能不受影响,也就是保持原始数据不变

hijack 发表于 2017-6-14 23:46

夏雨微凉 发表于 2017-6-14 21:23
这么说的话 python里边的变量是指针变量?比如 n2=n1,那么n1内容变了n2也会跟着变?

不会的,如果n1内容变了,比如变成n1=666,会另外出来一个内存地址装666,n1指向666的地址,n2还是指向原来的地址

zz0147 发表于 2017-6-14 20:18

{:1_912:}
python用的不多,希望看到你更多 的作品。
谢谢分享。

夏雨微凉 发表于 2017-6-14 21:23

这么说的话 python里边的变量是指针变量?比如 n2=n1,那么n1内容变了n2也会跟着变?

6767 发表于 2017-6-14 23:16

LZ这里有些时候可能要解释一下小整数缓冲区和字符串缓冲区会更好

瓦特蜀黍 发表于 2017-6-15 11:03

前排留名。膜败:victory:

micksoft 发表于 2017-6-15 11:55

有种说法是“传值类型与传址类型”,跟这个说的一样吧

夏雨微凉 发表于 2017-6-15 12:24

hijack 发表于 2017-6-14 23:46
不会的,如果n1内容变了,比如变成n1=666,会另外出来一个内存地址装666,n1指向666的地址,n2还是指向原 ...

哦,原来是这样

lxj12328 发表于 2017-6-17 17:47

谢谢分享。我也刚学

webboy89860 发表于 2017-6-17 19:53

看图的话可以使用:http://pythontutor.com/ 可视化观看python内的对象方法。
页: [1] 2
查看完整版本: 说说python下的赋值,深拷贝与浅拷贝