2011-10-18 39 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