在 Python 中,字符串(str)、元组(tuple)和数字(Number)是不可更改的对象,而列表(list)、字典(dict)等则是可以修改的对象。
- 不可变类型:变量赋值
a=5
后再赋值a=10
,这里实际是新生成一个int
值对象10
,再让a
指向它,而5
被丢弃,不是改变a
的值,相当于新生成了a
。 - 可变类型:变量赋值
la=[1,2,3,4]
后再赋值la[2]=5
则是将 listla
的第三个元素值更改,本身la
没有动,只是其内部的一部分值被修改了。
Python 函数的参数传递:
- 不可变类型:类似 c++ 的值传递,如整数、字符串、元组。如
fun(a)
,传递的只是a
的值,没有影响a
对象本身。比如在fun(a)
内部修改a
的值,只是修改另一个复制的对象,不会影响a
本身; - 可变类型:类似 c++ 的引用传递,如列表、字典、集合。如
fun(la)
,则是将la
真正的传过去,修改后fun
外部的la
也会受影响;
Python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
而深浅拷贝其实主要是针对可变对象来说的,先看如下示例:
lst1 = [1,2,3]
lst2 = lst1
lst2.append(4)
print(lst1 is lst2)
print(lst1)
'''
True
[1, 2, 3, 4]
'''
由于 lst2 = lst1
让 lst2
指向了 lst1
指向的地址,所以对 lst2
的操作实际上就是对 lst1
的操作。
如果我们希望 lst2
独立出来,让其和 lst1
指向不同的地址,此时就需要使用拷贝操作了。
copy 浅拷贝
要使用拷贝操作需要使用到 copy
模块,看下面示例:
from copy import *
lst1 = [1,2,3]
lst2 = copy(lst1)
lst2.append(4)
print(lst1 is lst2)
print(lst1)
print(lst2)
'''
False
[1, 2, 3]
[1, 2, 3, 4]
'''
可以看到,通过 copy
函数对 lst1
进行了拷贝,然后将返回值赋值给了 lst2
,随后对 lst2
的操作就没有影响到 lst1
了,因为此时 lst2
和 lst1
指向内存中的地址已经不同了。
我们再看一个示例:
from copy import *
lst1 = [1, 2, 3, ['a', 'b', 'c']]
lst2 = copy(lst1)
lst2[-1].append('d')
print(lst1 is lst2)
print(lst1[-1] is lst2[-1])
print(lst1)
print(lst2)
'''
False
True
[1, 2, 3, ['a', 'b', 'c', 'd']]
[1, 2, 3, ['a', 'b', 'c', 'd']]
'''
可以看到,我们依旧使用 copy
函数对 lst1
进行了拷贝,此时的 lst1
和之前不一样的是里层还有一个嵌套的列表,我们对 lst1
里层列表和 lst2
里层列表进行操作发现 lst1
和 lst2
虽然指向内存中不同的地址,但是 lst1
内层的列表和 lst2
内层的列表指向的地址还是相同的,即通过 copy
函数拷贝仅仅是对列表最外层元素进行了拷贝,所以它就叫浅拷贝。
deepcopy 深拷贝
如果我们希望拷贝时能将内层元素一同拷贝,此时就需要使用 copy
模块中的 deepcopy
函数了,也就是深拷贝,看如下示例:
from copy import *
lst1 = [1, 2, 3, ['a', 'b', 'c']]
lst2 = deepcopy(lst1)
lst2[-1].append('d')
print(lst1 is lst2)
print(lst1[-1] is lst2[-1])
print(lst1)
print(lst2)
'''
False
False
[1, 2, 3, ['a', 'b', 'c']]
[1, 2, 3, ['a', 'b', 'c', 'd']]
'''
特殊的元组
最外层为元组
上述深浅拷贝操作对 set 集合、list 列表、dict 字典都有效,有差异的就是元组了,看如下示例:
from copy import *
tup1 = (1, 2, 3, ['a', 'b', 'c'])
tup2 = copy(tup1)
print(tup1 is tup2)
‘’‘
True
’‘’
可以看到上述操作对 tup1
进行了浅拷贝并将返回值赋值给了 tup2
,但是最后发现它们依旧指向同一个地址,即浅拷贝在最外层是元组时是无效的,那么深拷贝呢?
from copy import *
tup1 = (1, 2, 3, ['a', 'b', 'c'])
tup2 = deepcopy(tup1)
print(tup1 is tup2)
‘’‘
True
’‘’
经过测试发现,深浅拷贝在最外层为元组时都无效。
内层的元组
最外层是元组时深浅拷贝是失效的,那么如果元组在列表或字典、集合内层的时候,是否能拷贝成功呢?
元组在内层,浅拷贝只能拷贝最外层,所以肯定是没戏了,那么下面来看下深拷贝能否拷贝内层元组的元素。
from copy import *
lst1 = [1, 2, 3, ('a', 'b', 'c')]
lst2 = deepcopy(lst1)
print(lst1 is lst2)
print(lst1[-1] is lst2[-1])
'''
False
True
'''
从结果可以看出深拷贝是可以拷贝内层元组的。
评论区