2011-10-18 16 views
1

次のコードは非常に単純ですが、何らかの理由でforループがロガーのすべてのハンドラを反復処理しません。しかし、else節にmy_logger.removeHandler(ハンドラ)を削除すると、for-loopはすべてのハンドラを反復処理します。私は何か悪いことをしている場合、任意のアイデア?Python 2.7.2がロガーのハンドラを正しく反復しない

import logging 
import sys 

stdf = logging.Formatter("%(message)s") 
filef = logging.Formatter("%(message)s") 
my_logger = logging.getLogger("file std logger") 
stdh = logging.StreamHandler(sys.stdout) 
stdh.setFormatter(stdf) 
my_logger.addHandler(stdh) 
fileh = logging.FileHandler("run.log", mode = 'w', encoding = "utf-16-le", delay = True) 
fileh.setLevel(logging.DEBUG) 
fileh.setFormatter(filef) 
my_logger.addHandler(fileh) 

my_logger.info("wow1") 
my_logger.info("test string1") 
my_logger.info("wow2") 
my_logger.info("test string2") 
my_logger.info("wow3") 
my_logger.info("test string3") 

for handler in my_logger.handlers: 
    print(handler) 
    if handler.__class__.__name__ == "FileHandler": 
     handler.flush() 
     handler.close() 
     my_logger.removeHandler(handler) 
    else: 
     handler.flush() 
     my_logger.removeHandler(handler) 

my_logger.handlers 

答えて

2

これは古典的な破壊的反復です。あなたがやっていることは:

>>> l= [0, 1, 2, 3, 4] 
>>> for n in l: 
...  l.remove(n) 
... 
>>> l 
[1, 3] 

この例では、2番目ごとの要素だけが削除されています。どうして?だから、ループiラウンド最初の時間は0アイテム0が削除されるで

>>> l= [0, 1, 2, 3, 4] 
>>> i= 0 
>>> while i<len(l): 
...  del l[i] 
...  i+= 1 
... 
>>> l 
[1, 3] 

:まあfor ... in構文は、実際には、伝統的なCスタイルのためのインデックスループと同じである、何が起こっているのか不明瞭項目1-4を1つ下に移動して新しい項目0-3にします。次回はループi1であるため、現在のアイテム1(2)が削除されます。元の1はジャンプされ、ループ内に残ります。

破壊的な繰り返しを避けるために、簡単な回避策は、リストのコピーを取り、オリジナルを変更しながらコピーを繰り返すことです:あなたがしようとしているときfilterやリストの内包表記を使用して

for handler in list(my_logger.handlers): 

は、一般的にシンプルなルートでありますリストから特定の項目を削除します。

+0

私はイテレータを開始した時点でイテレータがすべての要素を反復すると思っていました。つまり、「Pythonのfor-loopはC/C++と同じです」というチュートリアルは間違っています...これは、反復中のリストの変更が危険であることを意味します。これは、C/C++では配列ポインタを削除せずに配列ポインタが指す内容のみを削除するため、C/C++とは異なります。これを指摘してくれてありがとう。 – SCM

関連する問題