对赋值、浅拷贝、深拷贝的理解

  要理解赋值、浅拷贝、深拷贝,首先要对Python的内存管理进行了解。

  Python是基于值的内存管理,变量并不直接存储值:对于不可变对象(数值、字符串、元组)直接存储内存地址,多个变量指向同一个内存地址,可以节约内存空间;对于可变对象(列表、字典、集合等)存储的是其引用,通过对引用对象的修改,实现存储对象的可变性。

>>> a=1
>>> b=1
>>> print(id(a),id(b))
140708767110816 140708767110816
>>> a=[1,2]
>>> b=[1,2]
>>> print(id(a),id(b))
2433938250944 2433938965568

如上,对于数值(不可变对象),不同变量存储的是相同地址;对于列表(可变对象),不同变量存储时会开辟新的内存空间避免对可变对象修改时互相干扰。

  一、赋值

  赋值:对于不可变对象的值进行传递,直接赋予值的内存地址;对于可变对象的值进行传递,赋予的是原对象的引用地址

>>> a=1
>>> b=a
>>> print(a,b)
1 1
>>> print(id(a),id(b))
140708767110816 140708767110816
>>> a=[1,2]
>>> b=a
>>> print(id(a),id(b))
2433938965696 2433938965696

如上,直接进行赋值时传递变量存储的地址,但可变和不可变对象又有以下区分:

>>> a=1
>>> b=a
>>> a=2
>>> print(a,b)
2 1
>>> print(id(a),id(b))
140708767110848 140708767110816
>>> a=[1,2]
>>> b=a
>>> a.append(3)
>>> print(a,b)
[1, 2, 3] [1, 2, 3]
>>> print(id(a),id(b))
2433938965568 2433938965568

对于不可变对象,其内存存储的值是无法改变的,要想修改变量的值只能通过修改变量的地址;对于可变对象,可以通过修改其引用地址存储的值来实现修改变量的值。同时对于可变对象,只要其内容发生变化,所有通过引用地址指向它的变量的值都会发生相同变化,为了避免变量之间的相互干扰,这时候就需要对引用对象进行拷贝,而拷贝又分为浅拷贝深拷贝

 二、浅拷贝

  浅拷贝将可变对象内存储的地址拷贝到新的内存空间,将新内存空间赋予变量。

>>> import copy
>>> a = [1,(2,),'3',[4,5]]
>>> b = copy.copy(a)
>>> print(a,b)
[1, (2,), '3', [4, 5]] [1, (2,), '3', [4, 5]]
>>> print(id(a),id(b))
2433939144448 2433939144512
>>> for i,j in zip(a,b):
...     print(id(i),id(j))
...
140708767110816 140708767110816
2433937050256 2433937050256
2433937194288 2433937194288
2433938972288 2433938972288

此时,a、b的引用地址不同,所以对于a引用地址内存储的地址进行修改是不会影响b,如下

>>> a.append(6)
>>> print(a,b)
[1, (2,), '3', [4, 5], 6] [1, (2,), '3', [4, 5]]
>>> a[1]='2'
>>> print(a,b)
[1, '2', '3', [4, 5], 6] [1, (2,), '3', [4, 5]]

但是,由于a、b引用地址内存储了相同地址的列表,列表是可变对象,所以通过a或b对可变对象进行修改,都会引起a、b值的变化

>>> a[3].append(6)
>>> print(a,b)
[1, '2', '3', [4, 5, 6], 6] [1, (2,), '3', [4, 5, 6]]

所以,浅拷贝无法完全拷贝带有可变对象的可变对象,这时就引入了深拷贝

三、深拷贝

深拷贝将可变对象内存储的地址拷贝到新的内存空间,若可变对象内含有可变对象,则对其进行递归拷贝到新的内存地址直到没有可变对象,将新内存空间赋予变量。

>>> import copy
>>> a=[1,[2,3],[4,[5,6]]]
>>> b=copy.deepcopy(a)
>>> for i,j in zip(a,b):
...     print(id(i),id(j))
...
140708767110816 140708767110816
2433939143872 2433939143616
2433939144256 2433939144576
>>> a[1].append(7)
>>> print(a,b)
[1, [2, 3, 7], [4, [5, 6]]] [1, [2, 3], [4, [5, 6]]]
>>> a[2][1].append(8)
>>> print(a,b)
[1, [2, 3, 7], [4, [5, 6, 8]]] [1, [2, 3], [4, [5, 6]]]

这样a、b之间就互不干扰了

补充

python对于数值的内存空间重复管理仅预设了-5~256,超出此范围进行赋值时会开辟新的内存空间

>>> a=256
>>> b=256
>>> print(id(a),id(b))
140708767118976 140708767118976
>>> a=257
>>> b=257
>>> print(id(a),id(b))
2433938337712 2433938336720

如果想要节省内存空间,可以通过以下操作来实现

>>> a=258
>>> b=a
>>> print(id(a),id(b))
2433938336720 2433938336720
>>> a,b=258,258
>>> print(id(a),id(b))
2433938337712 2433938337712

猜你喜欢

转载自www.cnblogs.com/yundouguai/p/12292093.html