python学习笔记:别名(赋值)、浅拷贝、深拷贝

前提知识:

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[:])属于浅拷贝。
  • 。。。

猜你喜欢

转载自blog.csdn.net/xiaozhimonica/article/details/85701063