python forループremove同じlist


午後、pythonでLinuxのconfプロファイルを辞書dictに変換する際に奇妙な問題が発生しました.元のconfプロファイルにはコメント行(#で始まる行)がありませんでしたが、それを避けるために、#で始まる行を削除する操作が追加されました.実践結果は既存の認知を覆し,コード例を直接提示した.コードクリップ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

結果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

#結果2:['NAME="Ubuntu",'VERSION="14.04.3 LTS,Trusty Tahr"']
上記の2つのコードの結果は同じであるべきだと思っていたが,結果は異なる.
分析:
なぜならforループでremoveで同じリスト(ループで削除)を使用できないからです.removeというリストの要素があると、リストの長さが変化し、forループが影響を受けます(このpythonバージョン(2.7.1 x.xでは明らかなエラーはなく、著者はissueやバグだとは思わないかもしれませんが、ヒントを与えるのもいいでしょう).
解決策:
ループ内のlistまたはremove操作のlistの代わりに新しいリスト(list)を使用します.新しいリストを作成するには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

興味深いのはスライスも浅いコピーですが、スライスを利用して上記の機能を実現することもできます.コードは以下の通りです.
#!/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

上記のエラーが発生した例(forループでremoveで同じリストを使用)では、オブジェクトを修正すると必ずこのオブジェクトに影響を与えると認識され、オブジェクトを修正してもオブジェクト参照に影響を与えないには、オブジェクトのコピーが必要です.オブジェクトを変更し、元のオブジェクトに影響を与えないようにするには、オブジェクトのコピーが必要です.
追加の知識点:
浅いコピー(浅いコピー)について
オブジェクトの浅いコピー(shallow copy):オブジェクトはコピーされていますが、オブジェクト内の要素については参照が使用されます.
(1)、スライス[:]操作を使用してコピーする(注記:スライスはオブジェクトの最上位のみをコピーし、オブジェクトの次の階層に対しても参照する.例:[1,2,3,[4,5,6])
(2)、list/dir/setなどのファクトリ関数を用いたコピー
(3)、copy.copy()
(4)、=(割り当て)アクション(注記:原文はありません.ここでは新しく追加され、「オブジェクトの割り当ては実際にはオブジェクトの参照」に基づいて追加されます)
コンテナオブジェクトとその中のすべての要素(要素を含むサブ要素)をコピーする場合は、copyを使用します.deepcopyこの方法は時間と空間を消費します.しかし、完全にコピーする必要がある場合は、これが唯一の方法です.
注意:
1、数値、文字列、その他の「原子」タイプのオブジェクトなどの非コンテナタイプはコピーされていない.
2、メタ変数に原子型オブジェクトのみが含まれている場合は、copyを深くすることはできません.
深いレプリケーションと浅いレプリケーションについては、以下を参照してください.
『深いPython(4):深いコピーと浅いコピー』http://www.cnblogs.com/BeginMan/p/3197649.html
tag:python listメンバーの削除、pythonリスト要素の削除、python遍歴削除
--end--