Подтвердить что ты не робот

Удаление обработчиков из журналов регистрации python

Я играю с системой регистрации Python. Я заметил странное поведение при удалении обработчиков из объекта Logger в цикле. А именно, цикл for 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))

Чем объясняется это поведение? Является ли это ошибкой или я что-то упускаю?

4b9b3361

Ответ 1

Это не зависит от регистратора. Никогда не мутируйте (вставляйте/удаляйте элементы) список, в котором вы в настоящее время итерации. Если вам нужно, сделайте копию. В этом случае testLogger.handlers = [] должен сделать трюк.

Ответ 2

Если вы не хотите их удалять (спасибо за отзыв @CatPlusPlus):

testLogger.handlers = [
    h for h in testLogger.handlers if not isinstance(h, logging.StreamHandler)]