您的位置:首页 > 编程语言 > Python开发

Python 引用、浅拷贝、深拷贝解析

2020-02-07 06:20 197 查看

1、=的作用。

仅仅是地址的引用,当原列表或者新列表中任意元素改变,均会对另外一个产生影响

# 引用
# 本例中属于地址的引用,其中a和b共用同一块内存
# 当修改共用内存中的任意的内容是时,均会影响到另外的内容
a = [0, 1, 2, [3, 4]]
b = a

# 修改a[0]后,a[0]和b[0]都会改变
a[0] = 10
print("a:", a)
print("b:", b)

# 修改b[0]后,a[0]和b[0]都会改变
b[0] = 0
print("a:", a)
print("b:", b)

# 修改a[3][0]后,a[3][0]和b[3][0]都会改变
a[3][0] = 30
print("a:", a)
print("b:", b)

# 修改b[3][0]后,a[3][0]和b[3][0]都会改变
b[3][0] = 3
print("a:", a)
print("b:", b)

# 可以看到两个列表的内存地址相同
print("列表a的内存地址是:", id(a))
print("列表b的内存地址是:", id(b))
View Code

 

 

2、使用列表的copy()方法或者copy模块的copy()方法实现拷贝

a = ["a0", "a1", "a2", ["a3", "a4"]]
b = a.copy()
# print("a:", a)
# print("b:", b)
print("a的内存地址是:", id(a))
print("b的内存地址是:", id(b))
View Code

 

 

通过列表的copy()方法,可以得到一个与原列表相同的列表,当通过id()方法,查看两者的内存地址时,可以发现,两者的内存地址不同,可以当做将原列表拷贝了一份,而不是对于地址的引用。

但是,当对a列表或者b列表的前三个元素进行修改时,可以观察到仅修改了一个列表内的元素,对于另外一个列表的元素没有影响。比如

a[0] = 0
b[1] = 1
print(a) #[0, 'a1', 'a2', ['a3', 'a4']]
print(b) #['a0', 1, 'a2', ['a3', 'a4']]

可以看出,修改a[0]或者b[1]时均不会修改另一个列表的对应元素。然而有例外,看下面的例子

print(a)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
print(b)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
a[3][0] = 3
print(a)  # ['a0', 'a1', 'a2', [3, 'a4']]
print(b)  # ['a0', 'a1', 'a2', [3, 'a4']]
b[3][1] = 4
print(a)  # ['a0', 'a1', 'a2', [3, 4]]
print(b)  # ['a0', 'a1', 'a2', [3, 4]]

当修改a[3][0]时,b[3][0]也会跟着改变,当使用id()函数查看a[3][0]和b[3][0]时发现两者的内存地址相同,可以认为b[3][0]并不是从a那里复制了一份,而是直接指向了a[3][0]的内存地址,这样就可以解释为什么修改a列表的的列表时会影响到其他的了。

3、将所有的数据拷贝一份,需要使用copy模块的 deepcopy()方法

import copy
a = ["a0", "a1", "a2", ["a3", "a4"]]
b = copy.deepcopy(a)

使用deepcopy()方法实现列表的深拷贝,这种方式将原列表的元素拷贝一份,无论原列表内是否存在嵌套。

print(a)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
print(b)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
a[3][0] = 3
print(a)  # ['a0', 'a1', 'a2', [3, 'a4']]
print(b)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
b[3][1] = 4
print(a)  # ['a0', 'a1', 'a2', [3, 'a4']]
print(b)  # ['a0', 'a1', 'a2', ['a3', 4]]

修改内容时仅会改变自身,不会影响其他。

 

总结:

利用=的时候,仅仅是引用,而非拷贝,修改旧的或者新的都会影响另外一个,牵一发而动全身。

使用列表的copy方法或者使用copy模块的copy()方法,仅仅开辟一块新的内存空间,将原列表的第一层元素复制一份新的,而列表内的嵌套不会复制,仅仅是引用了内层列表的地址,属于空有其表(因为内层的无论通过新列表还是旧列表都能修改)

使用deepcoopy()方法拷贝列表,不仅开辟新空间,而且还将原列表的所有的元素都复制一份,无论原列表内是否存在嵌套的列表,属于形神具备(因为内层的列表元素不再是通过引用,而是真真正正的复制了一份新的)

PS:对于数字和字符串,赋值、浅拷贝和深拷贝的值都指向同一个内存地址。

转载于:https://www.cnblogs.com/June-King/p/10596210.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
站内首发文章 aoxi2020 发布了0 篇原创文章 · 获赞 0 · 访问量 222 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: