Python 2.7.2 doesn't properly iterate through logger's handlers
-
26-10-2019 - |
Pergunta
the following code is very simple, but for some reason, for-loop does not iterate through all handlers of the logger. however, for-loop does iterate through all handlers if we remove my_logger.removeHandler( handler ) in the else clause. any idea if I'm doing anything wrong?
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
Solução
This is a classic destructive iteration. What you are doing is:
>>> l= [0, 1, 2, 3, 4]
>>> for n in l:
... l.remove(n)
...
>>> l
[1, 3]
In this example only every second element is removed. Why? Well the for
...in
syntax obscures what's actually happening, which is the same as in a traditional C-style for-index loop:
>>> l= [0, 1, 2, 3, 4]
>>> i= 0
>>> while i<len(l):
... del l[i]
... i+= 1
...
>>> l
[1, 3]
So first time round the loop i
is 0. Item 0 gets removed, moving items 1–4 down one place to be the new items 0–3. Next time round the loop i
is 1
so the current item 1, which is 2
, is removed. The original 1
has been jumped and remains in the loop.
A simple workaround to avoid destructive iteration is to take a copy of the list and iterate the copy whilst changing the original:
for handler in list(my_logger.handlers):
Using filter
or list comprehensions is typically a simpler route when you are trying to remove certain items from a list.