前提知识:
python中变量的初始化操作执行三步:1. 开辟存储开辟一个内存空间:存储变量的地址,id(viriable);2.开辟一块内存空间(不连续),存储变量元素的地址;3.开辟一块内存空间,存储变量元素的值。
例如:a=[1,2,3],三步如下:
一、直接赋值 :
b=a,此时,b是a的别名,也就是说a就是b。
(1)第一种情况:
a=[1,2,3]
print("address of a is",id(a))
b=a
print("address of b is",id(b))
a+=[4]
print("a=",a)
print("b=",b)
print("Now address of a is",id(a))
print("Now address of b is",id(b))
此时输出:
address of a is 171219464
address of b is 171219464
a= [1, 2, 3, 4]
b= [1, 2, 3, 4]
Now address of a is 171219464
Now address of b is 171219464
b拷贝的是变量a的地址,即id(b)=id(a),当变量a增加元素时,变量a(也是变量b)的地址(id(a))不发生改变。
(2)第二种情况:
a=[1,2,3]
print("address of a is",id(a))
b=a
print("address of b is",id(b))
a=a+[4]
print("a=",a)
print("b=",b)
print("Now address of a is",id(a))
print("Now address of b is",id(b))
此时输出:
address of a is 171199984
address of b is 171199984
a= [1, 2, 3, 4]
b= [1, 2, 3]
Now address of a is 171218184
Now address of b is 171199984
这是因为,当执行a=a+[4]这条语句时,等号左边的a≠等号右边的a,即:生成了新的id(a),但id(b)=旧id(a)。
二、浅拷贝(shallow copy)
b=a.copy() or b=copy.cpoy(),仅拷贝a的父对象。即:1.开辟新空间存储变量b的地址;2.共用变量a各元素(一级元素)地址,即第一层。
(1)第一种情况:
a=[1,2,3,['alex','boby']]
b=a.copy()
print("address of a is",id(a))
print("address of b is",id(b))
print("id(a[3][0]) is",id(a[3][0]))
print("id(b[3][0]) is",id(b[3][0]))
a[3][0]='cindy'
print("Now address of a is",id(a))
print("Now address of b is",id(b))
print("a=",a)
print("b=",b)
print("id(a[3][0]) is",id(a[3][0]))
print("id(b[3][0]) is",id(b[3][0]))
print("id(a[3][1]) is",id(a[3][1]))
print("id(b[3][1]) is",id(a[3][1]))
此时输出:
address of a is 171514536
address of b is 171197784
id(a[3][0]) is 171277536
id(b[3][0]) is 171277536
Now address of a is 171514536
Now address of b is 171197784
a= [1, 2, 3, ['cindy', 'boby']]
b= [1, 2, 3, ['cindy', 'boby']]
id(a[3][0]) is 171277920
id(b[3][0]) is 171277920
id(a[3][1]) is 171277888
id(b[3][1]) is 171277888
执行b=a.copy(),使得id(b[0])~id(b[3])对应等于id(a[0])~id(a[3]);执行a[3][0]="cindy",则重新开辟内存空间,存储a[3][0]的地址,并重新开辟内存空间,存放"cindy",即重新对a[3][0]进行赋值。由于d(a[3])=id(b[3]),引用的是id(a[3][0])和id(a[3][1])的地址,故a与b均相应改变:
(2)第二种情况:
a=[1,2,3,['alex','boby']]
b=a.copy()
print("address of a is",id(a))
print("address of b is",id(b))
print("id(a[3][0]) is",id(a[3][0]))
print("id(b[3][0]) is",id(b[3][0]))
a[1]='cindy'
print("Now address of a is",id(a))
print("Now address of b is",id(b))
print("a=",a)
print("b=",b)
此时输出:
address of a is 171513936
address of b is 171514416
id(a[3][0]) is 171277536
id(b[3][0]) is 171277536
Now address of a is 171513936
Now address of b is 171514416
a= [1, 'cindy', 3, ['alex', 'boby']]
b= [1, 2, 3, ['alex', 'boby']]
执行a[0]="cindy",重新开辟内存空间,存储id(a[0]),并重新开辟内存空间,存储"cindy"。由于id(b[0])仍等于旧id(a[0]),故变量a发生改变,而变量b不发生改变。
三、深拷贝(deep copy)
b=copy.deepcopy(a),开辟一个内存空间存储变量b的地址,此后各级元素(父对象及子对象)地址均进行拷贝,因此,不论a如何变化,b均不发生改变(b引用的元素地址不变)。
# Create a 2d list
a = [ [ 1, 2, 3 ] , [ 4, 5, 6 ] ]
# Try to copy it
b = copy.deepcopy(a) # Correct!
# At first, things seem ok
print("At first...")
print(" a =", a)
print(" b =", b)
print(" id(a) is",id(a))
print(" id(b) is",id(b))
print(" id(a[0]) is",id(a[0]))
print(" id(b[0]) is",id(b[0]))
print(" id(a[0][0]) is",id(a[0][0]))
print(" id(b[0][0]) is",id(b[0][0]))
# Now modify a[0][0]
a[0][0]= 9
print("And after a[0][0] = 9")
print(" a =", a)
print(" b =", b)
print(" id(a[0]) is",id(a[0]))
print(" id(b[0]) is",id(b[0]))
print(" id(a[0][0]) is",id(a[0][0]))
print(" id(b[0][0]) is",id(b[0][0]))
此时输出:
At first...
a = [[1, 2, 3], [4, 5, 6]]
b = [[1, 2, 3], [4, 5, 6]]
id(a) is 171537712
id(b) is 171536792
id(a[0]) is 171513736
id(b[0]) is 171514536
id(a[0][0]) is 1492461760
id(b[0][0]) is 1492461760
And after a[0][0] = 9
a = [[9, 2, 3], [4, 5, 6]]
b = [[1, 2, 3], [4, 5, 6]]
id(a[0]) is 171513736
id(b[0]) is 171514536
id(a[0][0]) is 1492461888
id(b[0][0]) is 1492461760
浅拷贝vs.深拷贝:
其他:
- 切片拷贝(b=a[:])属于浅拷贝。
- 。。。