以下代码非常简单,但由于某种原因,for循环不会遍历记录器的所有处理程序。但是,如果我们在else子句中删除 my_logger.removeHandler(handler),for循环会遍历所有处理程序。我有什么不妥的想法吗?
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
答案 0 :(得分:2)
这是一个经典的破坏性迭代。你在做什么:
>>> l= [0, 1, 2, 3, 4]
>>> for n in l:
... l.remove(n)
...
>>> l
[1, 3]
在此示例中,仅删除每个第二个元素。为什么?那么for
... in
语法模糊了实际发生的事情,这与传统的C风格for-index循环相同:
>>> 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。下一轮循环i
为1
,因此删除当前项目1 2
。原始1
已被跳转并保持在循环中。
避免破坏性迭代的简单解决方法是获取列表的副本并在更改原始文件时迭代副本:
for handler in list(my_logger.handlers):
当您尝试从列表中删除某些项目时,使用filter
或列表推导通常是一种更简单的路径。