【问题标题】:Update a property in singleton (python)更新单例中的属性(python)
【发布时间】:2018-09-14 19:35:27
【问题描述】:

编辑:添加了 Ralf 使用 os.environ 的建议

尝试实现单例记录器,以便每次生成记录器实例时,它只会写入特定的文件名。直到指定新的文件名。

import logging

def singleton(myClass):                                             
    instances = {}                                                  
    def getInstance(*args,**kwargs):
        if myClass not in instances:
           instances[myClass] = myClass(*args,**kwargs)         
        return instances[myClass]                                   
    return getInstance                                              

@singleton
class Logger(object):
    def __init__(self):
        self.filename = os.environ['logger_filename']
        self.log = self.init_logger()

    def init_logger(self):
        fh = logging.FileHandler(self.filename + '.log')
        fmt = logging.Formatter("%(asctime)-6s: %(name)s - %(levelname)s - %(message)s)")
        fh.setFormatter(fmt)
        local_logger = logging.getLogger(self.filename)
        local_logger.setLevel(logging.DEBUG)
        local_logger.addHandler(fh)

        return local_logger

我上面的内容总是写在“test1.log”文件中。

os.environ['logger_filename'] = "test1"

a = Logger()
b = Logger()

a.log.debug("Hello A")
b.log.debug("Hello B")

os.environ['logger_filename'] = "test2"

c = Logger()
c.log.debug("Hello C")

由于单例将在实例中包含 Logger 类,因此它只会返回该实例而不运行 __init__

如果我使用以下内容更新单例:

def singleton(myClass):
    instances = {}
    def getInstance(*args,**kwargs):
        if myClass not in instances:
           instances[myClass] = myClass(*args,**kwargs)
        else:
            instances[myClass].update_logger()
        return instances[myClass]
    return getInstance

@singleton
class Logger(object):
    def __init__(self):
        self.filename = os.environ['logger_filename']
        self.log = self.init_logger()

    def init_logger(self):
        fh = logging.FileHandler(self.filename + '.log')
        fmt = logging.Formatter("%(asctime)-6s: %(name)s - %(levelname)s - %(message)s)")
        fh.setFormatter(fmt)
        local_logger = logging.getLogger(self.filename)
        local_logger.setLevel(logging.DEBUG)
        local_logger.addHandler(fh)

        return local_logger

    def update_logger(self):
        self.filename = os.environ['logger_filename']
        self.log = self.init_logger()


os.environ['logger_filename'] = "test1"


a = Logger()
b = Logger()

a.log.debug("Hello A")
b.log.debug("Hello B")

os.environ['logger_filename'] = "test2"

c = Logger()
c.log.debug("Hello C")

这将生成 2 个日志文件(test1 和 test2)。但是 test1 将包含两个“Hello A”和两个“Hello B”。我该如何解决这个问题?

【问题讨论】:

    标签: python singleton


    【解决方案1】:

    你提供的具体细节很少,所以我会给出一个应该可行的答案,但我不知道这是否是你想要的。

    如何使用os.environ 将当前文件名存储在环境变量中?

    可以修改singleton函数:

    import os
    
    def singleton(myClass):                                             
        ...
            if myClass not in instances:
               kwargs['filename'] = os.environ['logger_filename']  # may raise KeyError
               instances[myClass] = myClass(*args, **kwargs)         
        ...
    
    @singleton
    class Logger(object):
        def __init__(self, filename):
            self.filename = filename
        ...
    

    或者另一种选择是只修改记录器类:

    import os
    
    @singleton
    class Logger(object):
        def __init__(self):
            self.filename = os.environ['logger_filename']  # may raise KeyError
    

    使用这两个选项中的任何一个,您只需修改环境变量的值即可为您的记录器设置不同的目标:

    import os
    os.environ['logger_filename'] = 'f1.log'
    
    b = Logger() 
    b.log.debug("hello there")    # writes on 'f1.log'
    
    os.environ['logger_filename'] = 'f2222.log'
    
    c = Logger() 
    c.log.debug("hello there")    # writes on 'f2222.log'
    

    【讨论】:

    • 我想这行得通。正在考虑使用某种全局变量,没有想到这一点。这绝对是更好的方法。谢谢
    • 其实这行不通。由于单例只会返回具有旧文件名的实例,因此“c”仍将写入 f1.log,因为 init 不会从 Logger 运行并且单例只会返回实例
    • 嗯...一种解决方法是清除字典,例如更改环境变量后的Logger.instances.clear()
    • 我更新了问题,以便您可以看到我的尝试。如何从单例函数访问和清除实例?我似乎无法获得该属性
    • 尝试在local_logger.addHandler(fh)之前调用local_logger.handlers.clear()
    猜你喜欢
    • 1970-01-01
    • 2015-12-15
    • 2017-07-19
    • 1970-01-01
    • 2018-04-17
    • 1970-01-01
    • 2022-12-05
    • 2021-05-19
    • 1970-01-01
    相关资源
    最近更新 更多