下午在用python將Linux的conf配置文件轉(zhuǎn)化成字典dict時(shí)遇到了一個(gè)奇怪的問題,原先conf配置文件中沒有注釋行(以#開頭的行),后來為了避免這種情況,添加了一個(gè)對(duì)以#開頭的行刪除的操作。 實(shí)踐結(jié)果顛覆了已有的認(rèn)知,直接上代碼示例。
代碼片段1
#!/usr/bin/python # encoding: utf-8 # -*- coding: utf8 -*- import re list_to_test = ['# ', '# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"'] for member in list_to_test: if re.search('^#+.*', member) is not None: list_to_test.remove(member) print list_to_test
結(jié)果1:
['# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"']
代碼片段2
#!/usr/bin/python # encoding: utf-8 # -*- coding: utf8 -*- list_to_test = ['# ', '# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"'] list_to_test.remove('# ') list_to_test.remove('# conf') print list_to_test
# 結(jié)果2:
['NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"']
本以為上述兩個(gè)代碼的結(jié)果應(yīng)該是一樣的,結(jié)果不一樣。
分析:
原因是不能在for循環(huán)中用remove同一個(gè)列表(遍歷中刪除)。當(dāng)remove這個(gè)list中的元素時(shí),list的長度發(fā)生了變化,for循環(huán)就會(huì)受到影響(這個(gè)python版本(2.7.x沒有明顯的報(bào)錯(cuò),可能作者并不認(rèn)為這是一個(gè)issue或bug,但給點(diǎn)提示也是好的啊)。
解決辦法:
用一個(gè)新的列表(list)去代替循環(huán)中的list或者代替remove操作的list。在創(chuàng)建新的列表是可以用cpoy模塊中的deepcopy方法也可以用new_list = old_list[:]的方法,如下:
#!/usr/bin/python # encoding: utf-8 # -*- coding: utf8 -*- import re from copy import deepcopy old_list = ['# ', '# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"'] new_list = deepcopy(old_list) for member in new_list: if re.search('^#+.*', member) is not None: old_list.remove(member) print old_list
有趣(令人困惑)的是切片也是淺復(fù)制,但利用切片也可以實(shí)現(xiàn)上述功能,代碼如下:
#!/usr/bin/python # encoding: utf-8 # -*- coding: utf8 -*- import re old_list = ['# ', '# conf', 'NAME="Ubuntu"', 'VERSION="14.04.3 LTS, Trusty Tahr"'] new_list = old_list[:] for member in new_list: if re.search('^#+.*', member) is not None: old_list.remove(member) print old_list
上述導(dǎo)致錯(cuò)誤發(fā)生的例子(在for循環(huán)中用remove同一個(gè)列表)可以認(rèn)知為這個(gè)操作是修改對(duì)象勢(shì)必影響此對(duì)象,要想修改一個(gè)對(duì)象卻不影響此對(duì)象引用,則需要對(duì)象復(fù)制。如果你想修改一個(gè)對(duì)象,而且想讓原始的對(duì)象不受影響,那你就需要對(duì)象復(fù)制。
附加知識(shí)點(diǎn):
關(guān)于淺復(fù)制(淺拷貝)
對(duì)象的淺復(fù)制(shallow copy):它雖然復(fù)制了對(duì)象,但對(duì)于對(duì)象中的元素,依然使用引用.
(1)、使用切片[:]操作進(jìn)行拷貝 (注釋:切片只復(fù)制了對(duì)象的頂層,對(duì)對(duì)象的下一層還是引用,舉個(gè)例子:[1,2,3,[4,5,6]])
(2)、使用工廠函數(shù)(如list/dir/set)等進(jìn)行拷貝
(3)、copy.copy()
(4)、=(賦值)操作(注釋:原文沒有,此處是新添加的,根據(jù)“對(duì)象的賦值實(shí)際上是對(duì)象的引用”添加)
如果希望復(fù)制一個(gè)容器對(duì)象,以及它里面的所有元素(包含元素的子元素),使用copy.deepcopy這個(gè)方法會(huì)消耗一些時(shí)間和空間。不過,如果你需要完全復(fù)制,這是唯一的方法。
注意:
1、對(duì)于非容器類型(如數(shù)字、字符串、和其他‘原子'類型的對(duì)象)沒有被拷貝一說。
2、如果元組變量只包含原子類型對(duì)象,則不能深copy。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
