При импорте модулей происходят странные вещи - PullRequest
2 голосов
/ 27 сентября 2011

Мне очень не хочется задавать вопрос в этом заголовке, но я на самом деле не знаю, что происходит, вот и все.

Я делал другой проект, в котором я хотел использовать модуль регистрации. Код распределяется по нескольким файлам, и вместо создания отдельных объектов логгера для отдельных файлов я подумал о создании logs.py с содержимым

import sys, logging

class Logger:
    def __init__(self):
        formatter = logging.Formatter('%(filename)s:%(lineno)s %(levelname)s:%(message)s')
        stdout_handler = logging.StreamHandler(sys.stdout)
        stdout_handler.setFormatter(formatter)
        self.logger=logging.getLogger('')
        self.logger.addHandler(stdout_handler)
        self.logger.setLevel(logging.DEBUG)

    def debug(self, message):
        self.logger.debug(message)

и использовать этот класс как (в разных файлах.)

import logs
b = logs.Logger()
b.debug("Hi from a.py")
  1. Я сократил всю проблему, чтобы задать вопрос здесь. Теперь у меня есть 3 файла: a.py, b.py & main.py. Все 3 файла создают экземпляр класса logs.Logger и выводят отладочное сообщение.
  2. a.py & b.py импортирует «логи» и печатает их отладочное сообщение.
  3. main.py импорт журналов, a & b ; и печатает собственное отладочное сообщение.

Содержимое файла выглядит так: http://i.imgur.com/XoKVf.png

Почему отладочное сообщение из b.py печатается 2 раза и из main.py 3 раза?

Ответы [ 3 ]

2 голосов
/ 27 сентября 2011

Укажите имя для регистратора, в противном случае вы всегда используете root logger.

import sys, logging

class Logger:
    def __init__(self, name):
        formatter = logging.Formatter('%(filename)s:%(lineno)s %(levelname)s:%(message)s')
        stdout_handler = logging.StreamHandler(sys.stdout)
        stdout_handler.setFormatter(formatter)
        self.logger=logging.getLogger(name)
        self.logger.addHandler(stdout_handler)
        self.logger.setLevel(logging.DEBUG)

    def debug(self, message):
        self.logger.debug(message)

http://docs.python.org/howto/logging.html#advanced-logging-tutorial:

Хорошим соглашением для именования логгеров является использование уровня модуля. регистратор, в каждом модуле, который использует регистрацию, названный следующим образом:

logger = logging.getLogger(__name__)

2 голосов
/ 27 сентября 2011

logging.getLogger('') будет возвращать один и тот же объект каждый раз, когда вы вызываете его. Поэтому каждый раз, когда вы создаете экземпляр Logger (зачем здесь классы старого стиля?), Вы присоединяете еще один обработчик, в результате чего печатаете еще одну цель. Поскольку все ваши цели указывают на одно и то же, последний вызов .debug() будет печататься на каждом из трех StreamHandler объектов, указывающих на sys.stdout, в результате чего будут напечатаны три строки.

1 голос
/ 27 сентября 2011

Во-первых.Не создавайте свой собственный класс Logger.

. Просто настройте существующие классы регистратора с помощью существующих logging инструментов настройки.

Секунда.Каждый раз, когда вы создаете свой собственный класс Logger, вы также создаете новые обработчики и затем присоединяете новый (дублирующий) обработчик к корневому логгеру.Это приводит к дублированию сообщений.

Если у вас есть несколько модулей, которые должны (1) работать автономно и (2) также запускаться как часть более крупного составного приложения, вам необходимо это сделать.Это гарантирует, что конфигурация регистрации будет выполнена только один раз.

import logging
logger= logging.getLogger( __file__ ) # Unique logger for a, b or main


if __name__ == "__main__":
    logging.basicConfig( stream=sys.stdout, level=logging.DEBUG, format='%(filename)s:%(lineno)s %(levelname)s:%(message)s' )
    # From this point forward, you can use the `logger` object.
    logger.info( "Hi" )
...