【问题标题】:Thread-safe warnings in PythonPython 中的线程安全警告
【发布时间】:2011-08-31 21:59:38
【问题描述】:

我正在尝试找到一种记录警告消息的好方法,但会在其上附加只有函数调用者知道的信息。

我想举个例子就清楚了。

# log method as parameter

class Runner1(object):

    def __init__(self, log):
        self.log = log

    def run(self):
        self.log('First Warning')
        self.log('Second Warning')
        return 42


class Main1(object):

    def __init__(self):
        self._runner = Runner1(self.log)

    def log(self, message):
        print('Some object specific info: {}'.format(message))

    def run(self):
        print(self._runner.run())

e1 = Main1()
e1.run()

Main 对象有一个日志功能,可以在记录任何消息之前添加它自己的信息。此日志函数作为参数给出(在本例中为 Runner 对象)。一直携带这个额外的参数非常烦人,我想避免它。通常有很多对象/函数,因此我放弃了使用日志记录方法,因为我需要为每个对象创建不同的记录器。 (这是正确的吗?)

我尝试使用警告模块冒泡警告:

# warning module

import warnings

class Runner2(object):

    def run(self):
        warnings.warn('First Warning')
        warnings.warn('Second Warning')
        return 42


class Main2(object):

    def __init__(self):
        self._runner = Runner2()

    def log(self, message):
        print('Some object specific info: {}'.format(message))

    def run(self):
        with warnings.catch_warnings(record=True) as ws:
            warnings.simplefilter("always")
            out = self._runner.run()
            for w in ws:
                self.log(w.message)
        print(out)

e2 = Main2()
e2.run()

但根据文档,这不是线程安全的。

最后,我也尝试了一些生成器:

# yield warning

class _Warning(object):

    def __init__(self, message):
        self.message = message


class Runner3(object):

    def run(self):
        yield _Warning('First Warning')
        yield _Warning('Second Warning')
        yield 42


class Main3(object):

    def __init__(self):
        self._runner = Runner3()

    def log(self, message):
        print('Some object specific info: {}'.format(message))

    def run(self):
        for out in self._runner.run():
            if not isinstance(out, _Warning):
                break
            self.log(out.message)
        print(out)


e3 = Main3()
e3.run()

但是您必须修改 Runner.run 以产生(而不是返回)最终结果这一事实是不方便的,因为必须专门更改函数才能以这种方式使用(也许这将来会改变? PEP255 中的最后一个 QA)。此外,我不确定这种类型的实现是否还有其他问题。

所以我正在寻找的是一种不需要传递参数的冒泡警告的线程安全方式。我也希望没有警告的方法保持不变。添加一个特殊的结构,例如 yield 或 warning.warn 来冒泡警告就可以了。

有什么想法吗?

【问题讨论】:

    标签: python logging python-3.x warnings


    【解决方案1】:
    import Queue
    
    log = Queue.Queue()
    class Runner1(object):
    
        def run(self):
            log.put('First Warning')
            log.put('Second Warning')
            return 42
    
    class Main1(object):
    
        def __init__(self):
            self._runner = Runner1()
    
        def log(self, message):
            print('Some object specific info: {0}'.format(message))
    
        def run(self):
            out=self._runner.run()
            while True:
                try:
                    msg = log.get_nowait()
                    self.log(msg)
                except Queue.Empty:
                    break
            print(out)
    
    
    e1 = Main1()
    e1.run()
    

    产量

    Some object specific info: First Warning
    Some object specific info: Second Warning
    42
    

    【讨论】:

    • 感谢您的建议,但这仍然需要我将记录器提供给跑步者,与我的示例1相比,我没有看到任何好处。
    • @Hernan:您能提供一些您希望Runner 看起来像的伪代码吗?您如何期望在 Runner 中使用记录器而不将记录器显式传递给 Runner?通过使用全局变量?关闭?这两种选择似乎都对我很有吸引力......
    • 实际上,我的示例 2 和 3 是我所寻找的。保持跑步者简单,并为调用跑步者的函数增加一些复杂性。如果它是线程安全的,示例 2 将是完美的。如果我可以“返回 42”(而不是 yield 42),示例 3 将是完美的,因为这意味着没有警告的函数将在未修改的情况下运行。
    • @Hernan:有很多Runners(在不同的线程中)和一个Main吗?
    • @Hernan:我编辑了我的帖子,建议使用Queue.Queue
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    • 2021-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多