Преобразование функции в одноэлементный класс, возвращающий один экземпляр

#python #python-2.7 #logging #singleton #single-instance

#python #python-2.7 #ведение журнала #одноэлементный #одиночный экземпляр

Вопрос:

Я делаю этот проект на Python 2.7 и пытаюсь преобразовать эту функцию, которая возвращает объект ведения журнала. Я пытаюсь убедиться, что я могу использовать один и тот же экземпляр объекта через разные модули python, импортируя его без фактического создания новых экземпляров? Например, если я на самом деле импортирую модуль, в котором изначально был создан экземпляр, каждый раз, когда я его импортирую, создается новый экземпляр. Но я хочу использовать один и тот же исходный экземпляр во всех разных модулях, который был создан при первом запуске этого модуля, поскольку в моем файле журнала печатается несколько строк из-за нескольких экземпляров. Вот почему требуется одноэлементный класс в Python 2.7, но я не уверен, как преобразовать эту функцию в одноэлементный класс, чтобы она возвращала один экземпляр, и я мог использовать ее во всех своих различных модулях путем импорта без запуска новых экземпляров. Функция setLogger создает экземпляр logger, который вводит журналы в файл журнала file_name.

 def setLogger(file_name):
    logger = logging.getLogger(__name__)
    if not getattr(logger, 'handler_set', None):
        logger.setLevel(logging.INFO)
        stream_handler = logging.StreamHandler()
        file_handler = logging.FileHandler(file_name)
        formatter = logging.Formatter('%(message)s')
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
        logger.addHandler(stream_handler)
        logger.setLevel(logging.INFO)
        logger.propagate = False
        logger.handler_set = True
    return logger
  

Комментарии:

1. Эта функция уже ведет себя так, как вы ожидаете. Он всегда будет возвращать один и тот же объект logger, потому logging.getLogger что заботится об этом.

2. @zvone Нет, это не так. Каждый раз, когда я вызываю эту функцию, она создает другой экземпляр. Я вызываю модуль, содержащий эту функцию, из разных модулей. Поэтому каждый раз, когда он вызывается, он создает другой экземпляр object . Но я хочу, чтобы один и тот же экземпляр повсюду

3. __name__ это имя текущего модуля, поэтому для каждого модуля создается отдельный журнал. Вы можете использовать любую строку для имени. Попробуйте logger = logging.getLogger('MyLog') для каждого вызова экземпляра, чтобы он каждый раз использовал один и тот же журнал.

4. @Mike67 Я только что попробовал это, заменив name на ‘MyLog’, и это не сработало. Я явно распечатал созданные объекты, и все они были разными для разных модулей

Ответ №1:

Я не понимаю, почему при использовании одного и того же имени генерируются разные регистраторы.

Чтобы принудительно создать один экземпляр регистратора, получите регистратор один раз и сохраните его в глобальной переменной.

 logger = None  # global variable

def setLogger(file_name):
    global logger
    if logger == None:
       print('Creating logger')
       logger = logging.getLogger(__name__)  # only run once
    if not getattr(logger, 'handler_set', None):
        ........
    return logger
  

Я настроил несколько модулей, чтобы сузить проблему.

— mylogger.py —

   import logging

  logger = None  # global variable

  def setLogger(file_name="LogOut.log"):
      global logger
      if logger == None:
         print('Creating logger')
         logger = logging.getLogger(__name__)  # only run once
      if not getattr(logger, 'handler_set', None):
          logger.setLevel(logging.INFO)
          stream_handler = logging.StreamHandler()
          file_handler = logging.FileHandler(file_name)
          formatter = logging.Formatter('%(message)s')
          file_handler.setFormatter(formatter)
          logger.addHandler(file_handler)
          logger.addHandler(stream_handler)
          logger.setLevel(logging.INFO)
          logger.propagate = False
          logger.handler_set = True
      return logger
  

— modc.py —

   import mylogger

  def writelog():
      print("Hello from "   __name__)
      print(__name__, 'LogID:', id(mylogger.setLogger()))
      mylogger.setLogger().warning("Hello from "   __name__)
  

— modb.py —

   import mylogger
  import modc

  def writelog():
      print("Hello from "   __name__)
      print(__name__, 'LogID:', id(mylogger.setLogger()))
      mylogger.setLogger().warning("Hello from "   __name__)

  modc.writelog()
  

— moda.py —

   import mylogger

  def writelog():
      print("Hello from "   __name__)
      print(__name__, 'LogID:', id(mylogger.setLogger()))
      mylogger.setLogger().warning("Hello from "   __name__)
      
  import modb
  import modc

  writelog()
  modb.writelog()
  modc.writelog()
  

Я побежал moda.py . Вот результат. Регистратор создается один раз, и каждый модуль использует один и тот же экземпляр регистратора. Все сообщения сохраняются в один и тот же файл. Обратите внимание, что я использую python 3.7.

   Hello from modc
  Creating logger
  modc LogID: 1764613056456
  Hello from modc
  Hello from __main__
  __main__ LogID: 1764613056456
  Hello from __main__
  Hello from modb
  modb LogID: 1764613056456
  Hello from modb
  Hello from modc
  modc LogID: 1764613056456
  Hello from modc
  

Комментарии:

1. Эта логика имеет смысл, но вы должны понимать, что эта функция setLogger сама находится в модуле, который называется, скажем debugLogs.py . Итак, предположим, я пытаюсь настроить свой регистратор в файле с именем A.py Я импортирую debugLogs.py и настройте регистратор. Затем другой модуль B.py пытается настроить регистратор и вызывает debugLogs.py но даже для B.py регистратору изначально будет присвоено значение None, поэтому мы снова получаем разные объекты для разных файлов. Как вы считаете, логика должна быть такой, чтобы только при вызове из A.py logger настроен, и мы можем повторно использовать этот объект logger, созданный A.py через другие модули.