2011-09-20 12 views
29

Estoy jugando con el sistema de registro de Python. He notado un comportamiento extraño al eliminar manejadores de un objeto Logger en un bucle. A saber, mi bucle for elimina todos los controladores excepto uno. Llamada adicional al .removeHandler elimina el último controlador sin problemas. No se emiten mensajes de error durante las llamadas.Eliminando manejadores de los registradores de inicio de sesión de python

Este es el código de prueba:

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))  

espero que al final del bucle no hay controladores permanecerán en el objeto testLogger, sin embargo la última llamada a .removeHandler aparentemente falla, como puede verse a partir el resultado a continuación. Sin embargo, llamada adicional a esta función elimina el controlador como se esperaba. Aquí está la salida:

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 

Más interesante, si reemplazo del bucle original con el siguiente, el bucle funciona como se espera y no hay controladores permanecen en el objeto testLogger al final del bucle. Aquí es el bucle modificado:

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)) 

¿Cómo se explica este comportamiento? ¿Es esto un error o me estoy perdiendo algo?

+1

'por h en la lista (testLogger.handlers)' – sherpya

Respuesta

64

Esto no es un comportamiento específico del registrador. Nunca mute (inserte/elimine elementos) la lista en la que está iterando actualmente. Si lo necesita, haga una copia. En este caso, testLogger.handlers = [] debería hacer el truco.

+4

jejeje: Me perdí la solución obvia de establecer el lista a []. Creo que necesito más café –

3

Si no desea eliminarlos todos (gracias por the tip @CatPlusPlus):

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

Lo siento, encontré que esto no funcionó. Por ejemplo, no se puede usar para juzgar el tipo de controlador –

+1

@fat_cheng ¿Por qué no puede la instancia funcionar para ese fin? Parece que no tengo ningún problema para usar la sugerencia en esta respuesta. – AlanSE

+0

Estoy usando python3 en Ubuntu 16.04. Yo uso 'if (type (h) == logging.StreamHandler)]' en su lugar. –

Cuestiones relacionadas