Registro de Python: ¿Por qué se llama dos veces a __init__?

Estoy tratando de usar el registro de Python con un archivo de configuración y un controlador propio. Esto funciona hasta cierto punto. Lo que realmente me __init__ es que __init__ sea ​​llamado dos veces y __del__ se llame una vez. Cuando __init__ todo el archivo de configuración y creo el controlador directamente dentro del código, se llama una vez a __del__ y nunca se llama a __del__ .

Mis preguntas:

  1. ¿Por qué se llama __init__ dos veces?
  2. ¿Por qué se llama __del__ menos frecuencia que __init__ ?

El código:

 #!/bin/env python import logging import logging.handlers import logging.config class Test1TimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler): def __init__(self,filename): print "init called" logging.handlers.TimedRotatingFileHandler.__init__(self,filename, when='S', interval=86400, backupCount=8, encoding=None) def __del__(self): print "del called" if hasattr(logging.handlers.TimedRotatingFileHandler,"__del__"): logging.handlers.TimedRotatingFileHandler.__del__(self) logging.config.fileConfig('/root/test1.conf') logger = logging.getLogger("test1") 

El archivo de configuración:

 [formatters] keys: simple [handlers] keys: file [loggers] keys: root [formatter_simple] format: "%(message)s" [handler_file] class: test1.Test1TimedRotatingFileHandler args: ("/root/test1.log",) level=INFO [logger_root] level: INFO handlers: file qualname: test1 

La salida se ve así:

 init called init called del called 

El uso del depurador para obtener el seguimiento de la stack como lo sugiere Sentinal revela esto:

Primera llamada:

 > /root/test1.py(12)__init__() -> print "init called" (Pdb) where /root/test1.py(21)() -> logging.config.fileConfig('/root/test1.conf') /usr/local/python/2.6.4/lib/python2.6/logging/config.py(84)fileConfig() -> handlers = _install_handlers(cp, formatters) /usr/local/python/2.6.4/lib/python2.6/logging/config.py(156)_install_handlers() -> klass = _resolve(klass) /usr/local/python/2.6.4/lib/python2.6/logging/config.py(94)_resolve() -> found = __import__(used) /root/test1.py(21)() -> logging.config.fileConfig('/root/test1.conf') /usr/local/python/2.6.4/lib/python2.6/logging/config.py(84)fileConfig() -> handlers = _install_handlers(cp, formatters) /usr/local/python/2.6.4/lib/python2.6/logging/config.py(159)_install_handlers() -> h = klass(*args) > /root/test1.py(12)__init__() -> print "init called" (Pdb) c init called 

Segunda llamada:

 > /root/test1.py(12)__init__() -> print "init called" (Pdb) w /root/test1.py(21)() -> logging.config.fileConfig('/root/test1.conf') /usr/local/python/2.6.4/lib/python2.6/logging/config.py(84)fileConfig() -> handlers = _install_handlers(cp, formatters) /usr/local/python/2.6.4/lib/python2.6/logging/config.py(159)_install_handlers() -> h = klass(*args) > /root/test1.py(12)__init__() -> print "init called" 

Related of "Registro de Python: ¿Por qué se llama dos veces a __init__?"

  1. ¿Por qué se llama a init dos veces?

Si sigue el código del módulo de logging , verá que cuando carga el archivo de configuración de registro, crea una instancia de todos los manejadores (Primera instanciación).

En su código, declara su controlador como test1.Test1TimedRotatingFileHandler , así que cuando intenta importar su controlador, analiza el código en el módulo test1 … ¡¡así recrea el controlador !!

El código corregido guardará el uso de __name__ == '__main__' :

 #!/bin/env python import logging import logging.handlers import logging.config class Test1TimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler): def __init__(self,filename): print "init called" logging.handlers.TimedRotatingFileHandler.__init__(self,filename, when='S', interval=86400, backupCount=8, encoding=None) def __del__(self): print "del called" if hasattr(logging.handlers.TimedRotatingFileHandler,"__del__"): logging.handlers.TimedRotatingFileHandler.__del__(self) if __name__ == "__main__": logging.config.fileConfig('./test1.conf') logger = logging.getLogger("test1") 

2. ¿Por qué se llama del menos a menudo que init?

En general, el operador __del__ se llama cuando python-quiere, más exactamente, se llama cuando el recolector de basura decide recolectar el objeto en la basura; Esto no es necesariamente justo después de que lo sueltes.

Falta un if __name__ == "__main__": su código de configuración de registro. Se está ejecutando una segunda vez cuando el logging importa su módulo test1 para encontrar la referencia de clase.

Alternativamente, use el nombre __main__.Test1TimedRotatingFileHandler en el archivo de configuración, o bien coloque el código de configuración y la clase de controlador en diferentes archivos.