【问题标题】:Converting a function into a singleton class that returns one instance将函数转换为返回一个实例的单例类
【发布时间】:2020-10-18 23:59:21
【问题描述】:

我在 Python 2.7 上做这个项目,我正在尝试转换这个返回日志对象的函数。我试图确保我可以通过不同的 python 模块使用相同的对象实例,方法是导入它而不实际创建新实例?例如,如果我实际上导入了最初创建实例的模块,则每次导入它时都会创建一个新实例。但我想在所有不同的地方使用相同的原始实例 模块,这是我第一次运行该模块时创建的,因为由于多个实例,在我的日志文件中打印出多行。这就是为什么需要 Python 2.7 中的单例类的原因,但我不确定如何将此函数转换为单例类,以便它返回一个实例,并且我可以通过导入在所有不同的模块中使用它而不触发新实例。 setLogger 函数创建一个记录器实例,该实例将日志输入到 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

【问题讨论】:

  • 此函数的行为已经符合您的预期。它将始终返回相同的记录器对象,因为 logging.getLogger 负责处理。
  • @zvone 不,它没有。每次我调用这个函数时,它都会创建一个不同的实例。我正在从不同的模块调用包含此功能的模块。所以每次调用它都会创建不同的对象实例。但我想要始终使用相同的实例
  • __name__ 是当前模块的名称,这就是为每个模块创建不同日志的原因。您可以使用任何字符串作为名称。为每个实例调用尝试logger = logging.getLogger('MyLog'),以便每次都使用相同的日志。
  • @Mike67 我刚刚尝试将 name 替换为“MyLog”,但没有成功。我明确打印出创建的对象,它们对于不同的模块都是不同的

标签: python python-2.7 logging singleton single-instance


【解决方案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

【讨论】:

  • 这个逻辑是有道理的,但你必须明白这个 setLogger 函数本身就在一个叫做 debugLogs.py 的模块中。所以,假设我尝试在一个名为 A.py 的文件中设置我的记录器,我导入 debugLogs.py 并设置记录器。然后另一个模块 B.py 尝试设置记录器并调用 debugLogs.py 但即使对于 B.py 记录器最初也会设置为 None 所以我们再次为不同的文件获取不同的对象。你认为逻辑应该是这样的,只有当我们从 A.py 调用记录器时,我们才能通过其他模块重用 A.py 创建的记录器对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-12
  • 1970-01-01
  • 2015-05-29
  • 2018-05-05
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多