我在玩Python的日志记录系统。我在循环中从Logger对象中删除处理程序时发现了一个奇怪的行为。也就是说,我的for循环删除了除一个处理程序以外对.removeHandler
的额外调用可以顺利删除最后一个处理程序。呼叫期间不会发出任何错误消息。
这是测试代码:
import logging
import sys
logging.basicConfig()
dbg = logging.getLogger('dbg')
dbg.setLevel(logging.DEBUG)
testLogger = logging.getLogger('mylogger')
sh = logging.StreamHandler(sys.stdout)
fh = logging.FileHandler('mylogfile.log')
dbg.debug('before adding handlers: %d handlers'%len(testLogger.handlers))
testLogger.addHandler(fh)
testLogger.addHandler(sh)
dbg.debug('before removing. %d handlers: %s'%(len(testLogger.handlers),
str(testLogger.handlers)))
for h in testLogger.handlers:
dbg.debug('removing handler %s'%str(h))
testLogger.removeHandler(h)
dbg.debug('%d more to go'%len(testLogger.handlers))
#HERE I EXPECT THAT NO HANDLER WILL REMAIN
dbg.debug('after removing: %d handlers: %s'%(len(testLogger.handlers),
str(testLogger.handlers)))
if len(testLogger.handlers) > 0:
#Why is this happening?
testLogger.removeHandler(testLogger.handlers[0])
dbg.debug('after manually removing the last handler: %d handlers'%len(testLogger.handlers))
我希望在循环结束时,没有处理程序将保留在testLogger
对象中
对.removeHandler
的最后一次调用显然失败了,从下面的输出中可以看出。虽然
对此函数的额外调用将按预期删除处理程序。这是输出:
DEBUG:dbg:before adding handlers: 0 handlers
DEBUG:dbg:before removing. 2 handlers: [<logging.FileHandler instance at 0x021263F0>, <logging.StreamHandler instance at 0x021262B0>]
DEBUG:dbg:removing handler <logging.FileHandler instance at 0x021263F0>
DEBUG:dbg:1 more to go
DEBUG:dbg:after removing: 1 handlers: [<logging.StreamHandler instance at 0x021262B0>]
DEBUG:dbg:after manually removing the last handler: 0 handlers
更有趣的是,如果我用下面的循环替换原始循环,循环
按预期工作,并且在循环结束时没有处理程序保留在testLogger
对象中。
这是修改后的循环:
while len(testLogger.handlers) > 0:
h = testLogger.handlers[0]
dbg.debug('removing handler %s'%str(h))
testLogger.removeHandler(h)
dbg.debug('%d more to go'%len(testLogger.handlers))
这种行为有什么解释?这是一个错误还是我错过了什么?
答案 0 :(得分:87)
这不是特定于记录器的行为。 从不 mutate(插入/删除元素)您当前正在迭代的列表。如果需要,请复制。在这种情况下,testLogger.handlers = []
应该可以解决问题。
答案 1 :(得分:9)
如果您不想全部删除它们(感谢the tip @CatPlusPlus):
testLogger.handlers = [
h for h in testLogger.handlers if not isinstance(h, logging.StreamHandler)]
答案 2 :(得分:5)
而不是变异未记录的.handler
:
logging.getLogger().removeHandler(logging.getLogger().handlers[0])
通过这种方式,您可以通过官方api完全删除先前存在的处理程序对象。或删除所有处理程序:
logger = logging.getLogger()
while logger.hasHandlers():
logger.removeHandler(logger.handlers[0])
logging.config.dictConfig(config={'level': logging.DEBUG, 'handlers': []}
不仅删除而且阻止其创建。列表根目录将具有[]
处理程序
答案 3 :(得分:0)
我刚刚发现您也可以在日志记录.ini文件中执行此操作,使用以下块:
[logger_stpipe]
handlers=
propagate=1
qualname=stpipe
它基本上停用了给定记录器的所有处理程序。但它有点受限,因为你必须提前知道Logger的名字。