Python的可变对象与不可变对象
本文作者:杨慧琳
文字编辑:周聪聪
技术总编:张学人
好消息!!!爬虫俱乐部将于2019年7月5日至7月8日在武汉举行首期Python编程技术定制培训。本次培训采用理论与案例相结合的方式,旨在帮助零基础学员轻松入门Python,由浅入深学习和掌握Python爬虫技术,并明确未来更进一步的学习方向。
详细培训大纲及报名方式,请点击文末阅读原文呦~
在初学Python时,经常需要区分“可变对象”和“不可变对象”。其中,可变对象包括列表(list)、字典(dict)等;不可变对象包括整型(int)、浮点型(float)、字符串型(string)和元组(tuple)等。
在进行可变对象与不可变对象的介绍之前,首先分析Python中对象的存储方式。每个对象都有标识、类型和值。对象一旦创建,将生成一个唯一不变的标识,可以把标识理解为对象在内存中的内存地址(ID)。
关于“可变对象”和“不可变对象”的解释较多,为便于理解,我们进行如下定义:
① 可变对象:在ID不变的情况下,可以改变对象的值。
② 不可变对象:对象的值一旦改变,其ID也改变。
在Python中,参数传递模式为共享传参(call by sharing),即函数的各个形式参数获得实参中各个引用的副本。这种方案的结果是,函数可能会修改作为参数传入的可变对象,但无法修改那些对象的标识(即不能把一个对象替换成另一个对象)。
因此,对于当传递的是可变对象时,进行+=或*=等增量赋值是作用于对象本身,就地修改变量值。当传入的是不可变类型时,由于无法真正修改,往往创建新的对象,并赋予其新值。若变量是原对象的最后一个引用,原对象将被当作垃圾回收。
接下来,我们分别以列表(list)和元组(tuple)为例,直观呈现可变对象与不可变对象的区别。
(1)列表的可变性
lst = [1,3,5,7,9]
print('ID:',id(lst))
lst.append([11,13,15]) #在列表尾部增加一个新的子列表
print('lst =',lst)
print('new_ID:',id(lst)) #输出新的内存地址可见,将子列表[11,13,15]合并到原列表lst中后,列表值发生变化,但其内存地址ID保持不变。这是由于列表是可变对象,允许在其指向的内存空间就地修改元素,而不生成一个新的对象。
(2)元组的不可变性
t = (1,3,5,7,9,11)
print('ID:',id(t))
t += (15,17) #往元组内加入新的元素
print('t =',t)
print('new_ID:',id(t))
可见,将元素15、17加入元组t后,t的ID在前后发生变化。这是由于元组本身不可变,在进行“+=”运算符操作时,将创建一个新元组,然后重新绑定给对象t,相当于执行“t=t+(15,17)”,前后并不是同一个对象。
需注意的是,这里的可变性与不可变性是针对具体对象而言。以元组为例,其更确切的定义应是相对不可变性。与多数Python集合(列表、字典、集,等等)一样,元组保存的是对象的引用。如果引用的元素是可变的,即便元组本身不可变,元素依然可变。也就是说,元组的不可变性实质上是指tuple数据结构的物理内容(即保存的引用)不可变,与引用的对象无关。
如下,元组tup的最后一个元素t[-1]引用的是可变列表对象,我们可以直接改变这一元素的值,并令整个元组tup的值发生变化。但由于该可变列表元素的标识(ID)不变,元组的ID也不改变,相当于就地修改了元组中特定元素的值。
tup = (1,3,5,[7,9,11])
print('元组tup的ID:%d; 元素tup[-1]的ID:%d' %(id(tup),id(tup[-1])))
tup[-1][1]=10
print('tup =',tup)
print('元组tup的new_ID:%d; 元素tup[-1]的new_ID:%d' %(id(tup),id(tup[-1])))
我们进一步尝试修改元组本身的数据结构,在其后面增加新的元素。此时,元组tup的ID发送变化,表示内存中新生成了一个对象,其值为“tup=tup+(15,17)”。若没有其他变量名或对象引用的话,原对象占用的内存空间将被回收。
tup+= (15,17)
print('tup=',tup)
print('元组tup的new_ID:%d; 元素tup[-3]的new_ID:%d' %(id(tup),id(tup[-3])))
综上,若不可变集合保存了可变元素的引用,当可变元素的值发生变化后,不可变集合也会随之改变,但其所含对象的标识不变。
对爬虫俱乐部的推文累计打赏超过1000元我们即可给您开具发票,发票类别为“咨询费”。用心做事,只为做您更贴心的小爬虫!
往期推文推荐
关于我们
微信公众号“爬虫俱乐部”分享实用的stata命令,欢迎转载、打赏。爬虫俱乐部是由李春涛教授领导下的研究生及本科生组成的大数据分析和数据挖掘团队。
此外,欢迎大家踊跃投稿,介绍一些关于stata的数据处理和分析技巧。
投稿邮箱:statatraining@163.com
投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到关于stata分析数据的问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。