我有以下mcve

import logging
class MyGenIt(object):
    def __init__(self, name, content):
        self.name = name
        self.content = content
    def __iter__(self):
        with self:
            for o in self.content:
                yield o
    def __enter__(self):
        return self
    def __exit__(self,  exc_type, exc_value, traceback):
        if exc_type:
            logging.error("Aborted %s", self,
                          exc_info=(exc_type, exc_value, traceback))

下面是使用示例:
for x in MyGenIt("foo",range(10)):
    if x == 5:
        raise ValueError("got 5")

我希望logging.error报告ValueError,但它报告GeneratorExit
ERROR:root:Aborted <__main__.MyGenIt object at 0x10ca8e350>
Traceback (most recent call last):
  File "<stdin>", line 8, in __iter__
GeneratorExit

当我在GeneratorExit中捕获__iter__时:
def __iter__(self):
    with self:
        try:
            for o in self.content:
                yield o
        except GeneratorExit:
            return

当然不会记录任何内容,因为__exit__是用exc_type=None调用的。
为什么我在GeneratorExit中看到ValueError而不是__exit__
我该怎么做才能获得所需的行为,即ValueError中的__exit__

最佳答案

简单地说,您可以从生成器中“调出上下文管理器”,只需更改3行即可获得:

import logging
class MyGenIt(object):
    def __init__(self, name, content):
        self.name = name
        self.content = content

    def __iter__(self):
        for o in self.content:
            yield o

    def __enter__(self):
        return self

    def __exit__(self,  exc_type, exc_value, traceback):
        if exc_type:
            logging.error("Aborted %s", self,
                          exc_info=(exc_type, exc_value, traceback))


with MyGenIt("foo", range(10)) as gen:
    for x in gen:
        if x == 5:
            raise ValueError("got 5")

一个上下文管理器,它还可以充当迭代器——并捕获调用方代码异常,如ValueError。

关于python - 如何使用GeneratorExit?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50691616/

10-12 14:28