对于传参数还是传引用还是这个问题,在上学C语言的时候就被烦过一段时间。那在python中,参数传递是传参还是传引用呢?拷贝为什么还分浅拷贝和深拷贝呢?区别是什么呢?本文主要来介绍python中的拷贝。
在了解拷贝之前,我们先了解下python中的数据类型。
python中的内置数据类型,分为可变和不可变两种。
可变:列表,字典,集合
不可变:整数,浮点数,字符串,元组
比较好理解,列表是可以进行增删改的,而整数1就是1,1不能改为2。
nums = [1,2,3,4,5]
id(nums)
nums.append(6)
id(nums)
nums的值变量,但是内存地址没变
a=1
id(a)
a=2
id(a)
a的值变了,执行不同的整数,内存地址也就变了
def add_str(_str):
_str += "def"
return _str
def add_list(_list, val):
_list.append(val)
return _list
str = "abc"
add_str(str)
==> abc
nums = [1,2,3]
add_list(nums, 4)
==>[1,2,3,4]
以上例子不可变类型做为参数传入,变量没有被改变;可变类型传入后,变量被改变了。
原始是因为在python中参数传递传入的是变量所指对象的引用,由于字符串是不可变变量,函数内对字符串进行了修改就需要新开一个内存地址,保存新的字符串,所以不会对传入变量进行修改。
而列表是可变类型,变量进行了修改,但是内存地址还是同一个地址,所以传入的变量也发生了变化。
import copy
a = [1,2,3,4]
b = a.copy()
b.append(5)
id(a)
id(b)
==>a=[1,2,3,4]
==>b=[1,2,3,4,5]
浅拷贝是创建一个新的容器,对于对象中的元素,还是使用原始元素的引用。
上面的例子,b是一个新的容器,所以可变列表修改后,不会影响a。
import copy
a = [1,[2],3,4]
b = a.copy()
b[1]=0
id(a)
id(b)
==>a=[1,[0],3,4]
==>b=[1,[0],3,4]
以上情况,由于a[1]和b[1]是同一个引用,我们修改b[1],还是会影响a[1]的,这种情况就需要使用深拷贝。
深拷贝和浅拷贝一样会创建一个新的容器,并且对于对象中的元素也会重新生成一个新的对象。
a=[1,[2,3],4,5]
b = copy.deepcopy(a)
b[1].append(0)
==>
a=[1,[2,3],4,5]
b=[1,[2,3,0],4,5]
赋值和深拷贝浅拷贝不一样,它是并没有创建任何新的容器的。我们可以看看传递参数是肤质还是拷贝。
import copy
def fun(b):
print("arg id = ", id(b))
b[0]=2
a=[1,2,3,4]
a_copy=a.copy()
print("a id = ",id(a))
print("a_copy id = ",id(a_copy))
fun(a)
print(a)
==>
a id = 4387526848
a_copy id = 4387526688
arg id = 4387526848
[2, 2, 3, 4]
通过以上打印可以看出,传参数是一个赋值过程,并没有创建新的容器,只有拷贝才会创建新的容器,所以这种情况下一定要注意,可变变量在函数体中的修改是会影响变量的。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。