2011-10-18 54 views
1

以下代碼非常簡單,但由於某些原因,for-loop不會遍歷記錄器的所有處理程序。但是,如果我們刪除else子句中的my_logger.removeHandler(處理程序),則for循環遍歷所有處理程序。任何想法,如果我做錯了什麼?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] 

在這個例子中只有每個第二個元素被刪除。爲什麼?井for ... in語法掩蓋了所發生的情況,這是相同的指數循環傳統的C風格:

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

所以第一次輪循環i 0 0項被刪除,將項目1-4下移到一個地方成爲新項目0-3。下一次循環i1,因此當前項目1(即2)被刪除。原來的1已被跳轉並保持在循環中。

一個簡單的解決辦法,以避免破壞性的迭代是採取列表的副本和重複拷貝,而改變原有:

for handler in list(my_logger.handlers): 

使用filter或列表理解通常是當你試圖爲更簡單的途徑從列表中刪除某些項目。

+0

我認爲迭代器在迭代器開始時迭代遍歷所有元素。這意味着說「Python的for-loop與C/C++相同」的教程是錯誤的......這意味着在迭代過程中修改列表是危險的。這與C/C++不同,因爲C/C++只刪除數組指針指向的內容而不刪除數組指針。感謝您指出了這一點。 – SCM