Domanda

il seguente codice è molto semplice, ma per qualche ragione, per-ciclo non iterate lo fa attraverso tutti i gestori del logger. tuttavia, per-loop iterate fa attraverso tutti i gestori se togliamo my_logger.removeHandler (handler) nella clausola else. qualche idea se sto facendo qualcosa di sbagliato?

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
È stato utile?

Soluzione

Questa è un'iterazione distruttiva classico. Quello che state facendo è:

>>> l= [0, 1, 2, 3, 4]
>>> for n in l:
...     l.remove(n)
... 
>>> l
[1, 3]

In questo esempio solo ogni secondo elemento viene rimosso. Perché? Beh, la for ... in sintassi modo oscura ciò che è realmente accadendo, che è la stessa come in un tradizionale stile C ciclo per-index:

>>> l= [0, 1, 2, 3, 4]
>>> i= 0
>>> while i<len(l):
...     del l[i]
...     i+= 1
...
>>> l
[1, 3]

Quindi prima volta intorno al i loop è 0. Articolo 0 viene rimosso, oggetti in movimento 1-4 basso di una posizione di essere i nuovi elementi 0-3. Prossima volta il i loop è 1 così l'elemento corrente 1, che è 2, viene rimosso. Il 1 originale è stato saltato e resti nel circuito.

Una soluzione semplice per evitare l'iterazione distruttivo è quello di prendere una copia della lista e iterare la copia, mentre l'originale cambiando:

for handler in list(my_logger.handlers):

Utilizzando filter o list comprehension è tipicamente un percorso più semplice quando si sta tentando di rimuovere alcuni elementi da un elenco.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top