python - logger.removeHandler(logger.handlers[0]) 如何抛出 ValueError : list. 删除(x) : x not in list?

标签 python django list logging

我正在尝试调试别人的 Python 代码中的异常,但我不是 Python 专家。该代码尝试刷新并删除标准 Python 记录器上的所有处理程序:

def restart_logging(logger_id):
    logger = logging.getLogger(logger_id)
    while logger.handlers:
        handler = logger.handlers[0]
        handler.flush()
        logger.removeHandler(handler)
    init_logging(logger_id)

这会引发异常:

File "/usr/lib64/python2.6/logging/__init__.py", line 1208, in removeHandler
    self.handlers.remove(hdlr)
ValueError: list.remove(x): x not in list

我已经查看了 StackOverflow 的其他“x 不在列表中”问题,它们都属于这两类:

  • 多次删除同一项目(通常是因为执行 for x in list: list.remove(x) 而不是 while list: list.remove(list[0]) )
  • 删除列表中从未出现过的项目

我不明白这两者在这里如何适用。

首先,使用 while 循环:当仍然有处理程序时,获取第一个处理程序(成功,否则会出现 IndexError),刷新它,删除它。即使删除了列表中的多个条目,这也是一个 while 循环测试列表是否仍然有条目,而不是迭代(可能删除)对象的 for 循环。

查看logging模块源代码,它只调用remove()一次,甚至检查处理程序是否在调用remove()之前的列表:

def removeHandler(self, hdlr):
    """
    Remove the specified handler from this logger.
    """
    if hdlr in self.handlers:
        #hdlr.close()
        hdlr.acquire()
        try:
            self.handlers.remove(hdlr)
        finally:
            hdlr.release()

此代码作为 Django Web 应用程序的一部分执行。我可以理解,例如,如果它是一个 Java J2EE 应用程序,其中两个线程可以同时访问同一个列表,并且没有锁来使“获取第一项并删除它”成为原子操作,因此两个线程都会看到相同的内容列表中的元素,但只有一个会删除它,另一个会失败,因为线程删除了第一个线程的“此项目是否在列表中”和“从列表中删除此项目”之间的元素。

但是,据我了解,Python 没有并发性,并且使用全局解释器锁来阻止同时发生多件事情。所以这应该是不可能的。

所以,我无法弄清楚为什么 list.remove(x): x not in list 在这里发生,而且我无法制作一个可靠发生的测试用例。我可以做些什么来进一步理解这个问题?

最佳答案

虽然单个操作可能是原子的(以及您可能已经注意到的 list.remove 等操作,但这只是由于 CPython 的实现细节而造成的), removeHandler当然不是。在 Python 2.6 实现中(您已经发布了非常有帮助的内容),上下文切换可以在 if 之后发生。语句和锁获取之前(假设这就是 hdlr.acquire() 所做的)。因此,如果两个线程同时调用此函数,则当一个线程随后释放其对 GIL 的持有而另一个线程运行整个过程直至完成时,肯定会引发异常(原始线程将从 if、处理程序内部继续)仍然指向原始的,它将获取 IO 锁,然后尝试将其从列表中删除,从而导致不必要的异常)。

在 Python 2.7 中,此问题已得到修复,removeHandler方法改为:

    def removeHandler(self, hdlr):
        """
        Remove the specified handler from this logger.
        """
        _acquireLock()
        try:
            if hdlr in self.handlers:
                self.handlers.remove(hdlr)
        finally:
            _releaseLock()

请注意现在如何在 if 语句之前获取锁。

关于python - logger.removeHandler(logger.handlers[0]) 如何抛出 ValueError : list. 删除(x) : x not in list?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46217752/

相关文章:

python - 使用 Amazon Textract 分析 PDF 的特定页面

python - Django:根据 URL 在 settings.py 中动态设置 SITE_ID?

python - 如果二维列表的元素不在范围内,如何处理错误

python - 当我尝试从 python 列表中删除元素(pydot 对象)时出现错误

python - 识别非常低级别的图片并在 Python 中将其着色为纯黑色

python - 在 scipy 中使用大 F 阶矩阵进行 dgemm 段错误

python - 如何播种 Django 项目? - 向项目中插入一堆数据进行初始化

python - 如何在 Python 中对号码列表进行排序?

python - 如何将概率列表转换为二进制值

django:使用通用 View 类将额外参数传递给模板