阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Python 中变量赋值传递时的引用和拷贝介绍

32次阅读
没有评论

共计 1840 个字符,预计需要花费 5 分钟才能阅读完成。

导读 Python 赋值过程中不明确区分拷贝和引用,一般对静态变量的传递为拷贝,对动态变量的传递为引用。

Python 中变量赋值传递时的引用和拷贝介绍

曾经看到这样一个问题,一个字典中的元素是列表,将这个列表元素赋值给一个变量,然后修改这个列表中元素的值,结果发现,字典中那个列表也同样修改了。那个问题如下:

dict = {'a':[1,2,3,4,5],'b':2}
x = dict['a']
for i in range(5):
    x[i] = 0
print(dict['a'])

程序运行结果如下:

[0, 0, 0, 0, 0]

这儿涉及到 Python 赋值到底是引用还是拷贝一份的问题,即赋值时是传值还是传址。上面问题是将 ”a” 的值赋给了 x 出现了上述情况,如果是将 ”b” 的值赋给了 x,当我们修改 x 的值时,字典 dict 的值并不受影响。

>>> dict = {'a':[1,2,3,4,5],'b':2}
>>> x = dict['b']
>>> x
2
>>> x=x+3
>>> x
5
>>> dict
{'a': [1, 2, 3, 4, 5], 'b': 2}
>>>

那么问题来了,变量赋值传递时什么情况下是传值(拷贝),什么情况下是传址(引用)呢?

直接拷贝

当我们不知道是引用还是拷贝的情况下,可以显式的拷贝。比如字典对象本身都具有拷贝的方法:

x=dict.copy()

没有拷贝方法的对象,也是可以拷贝的。这儿我们引入一个深拷贝的概念,深拷贝——即 python 的 copy 模块提供的一个 deepcopy 方法。深拷贝会完全复制原变量相关的所有数据,在内存中生成一套完全一样的内容,在这个过程中我们对这两个变量中的一个进行任意修改都不会影响其他变量。还是上面的代码,如果改成如下:

import copy
dict = {'a':[1,2,3,4,5],'b':2}
x = copy.deepcopy(dict['a'])
for i in range(5):
    x[i] = 0
print(dict['a'])

运行结果 dict 值不受影响。

除了深拷贝,copy 模块还提供一个 copy 方法,称其为浅拷贝,对于简单的对象,深浅拷贝都是一样的,上面的词典对象的 copy 方法就是浅拷贝。

>>> dict
{'a': [8, 2, 3, 4, 5], 'b': 4}
>>> dd=copy.copy(dict)
>>> dd
{'a': [8, 2, 3, 4, 5], 'b': 4}
>>> dd['a'][0]=7
>>> dd
{'a': [7, 2, 3, 4, 5], 'b': 4}
>>> dict
{'a': [7, 2, 3, 4, 5], 'b': 4}
>>> ee=dict.copy()
>>> ee
{'a': [7, 2, 3, 4, 5], 'b': 4}
>>> ee['a'][0]=9
>>> ee
{'a': [9, 2, 3, 4, 5], 'b': 4}
>>> dict
{'a': [9, 2, 3, 4, 5], 'b': 4}
>>> ee['b']=5
>>> ee
{'a': [9, 2, 3, 4, 5], 'b': 5}
>>> dict
{'a': [9, 2, 3, 4, 5], 'b': 4}
>>>

浅拷贝时改变第一层次相互不受影响(上例中词典 b 值的修改),第二层次(上例中词典 a 的列表值修改)就相互影响了,改一个,其他跟着变。看看 id 吧:

>>> id(dict)
20109472
>>> id(dd)
20244496
>>> id(ee)
20495072
>>> id(dd['a'])
20272112
>>> id(ee['a'])
20272112
>>> id(dict['a'])
20272112
>>>

可见词典各个拷贝的 id 是不同的,但词典 a 值的 id 是相同的。如果我们需要真正意义的拷贝,就用深拷贝吧。

传递规则

Python 赋值过程中不明确区分拷贝和引用,一般对静态变量的传递为拷贝,对动态变量的传递为引用。(注,对静态变量首次传递时也是引用,当需要修改静态变量时,因为静态变量不能改变,所以需要生成一个新的空间存储数据)。

  1. 字符串,数值,元组均为静态变量
  2. 列表,字典为动态变量

变量有时比较复杂,存在组合现象,比如字典中包含列表,列表中包含字典,但赋值时,总是属于某个类型。如果实在不清楚状况,可以试验一下,用 id() 这个函数看看,如果是引用,两个变量指向的地址是相同的。例如:

>>> a=6
>>> id(a)
10413476
>>> b=a
>>> id(b)
10413476
>>> b=8
>>> id(b)
10413452
>>>

修改变量 b 之前,a 和 b 指向的地址是相同的,修改 b 后,地址就变了。

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-07-25发表,共计1840字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中