一、赋值
- str例子
>>> a = 'hello'
>>> b = 'hello'
>>> c = a
>>> [id(x) for x in (a,b,c)]
[42654216, 42654216, 42654216]
a,b,c三者地址一样,相当于a=b=c。赋值系统先给变量或对象(这里的hello)分配了内存,然后将地址赋给a,b,c。所以他们的地址是相同的。
>>> a = 'world'
>>> [id(x) for x in (a,b,c)]
[42654384, 42654216, 42654216]
>>> print(a,b,c)
world hello hello
这时只有a的地址和值变了,但是b,c地址和值都没有变。因为str的不可变性,a要重新赋值则需重新开辟内存空间,所以a的值改变,a指向的地址改变。b, c由于'hello'的不变性,不会发生改变。
- list例
>>> a = ['hello']
>>> b = ['hello']
>>> c = a
>>> [id(x) for x in (a,b,c)]
[42670920, 42671816, 42670920]
但是这种情况却不一样了,a和b的地址不同。为何?
因为str是不可变的,所以同样是'hello'只有一个地址,但是list是可变的,所以必须分配两个地址。
>>> a[0] = 'world'
>>> [id(x) for x in (a,b,c)]
[42670920, 42671816, 42670920]
>>> print(a,b,c)
['world'] ['hello'] ['world']
这时a,c的值和地址均改变,但二者仍相同,b不改变。由于list的可变性,所以修改list的值不需要另外开辟空间,只需修改原地址的值。所以a,c均改变。
二、浅拷贝与深拷贝
- 程序
import copy
a = [1,2,3,4,['a','b']] #原始对象
b = a #赋值
c = copy.copy(a) #浅拷贝
d = copy.deepcopy(a) #深拷贝
a.append(5)
a[4].append('c')
print('a = ',a)
print('b = ',b)
print('c = ',c)
print('d = ',d)
- 结果
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
- copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。
- copy.deepcopy 深拷贝 拷贝对象及其子对象
总结:
赋值是将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 )。
浅拷贝是在另一块地址中创建一个新的变量或容器,但是容器内的元素的地址均是源对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素( 新瓶装旧酒 )。
深拷贝是在另一块地址中创建一个新的变量或容器,同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本。也就是说( 新瓶装新酒 )。