【发布时间】:2018-11-14 10:34:09
【问题描述】:
我有以下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
当我在__iter__ 中捕获GeneratorExit 时:
def __iter__(self):
with self:
try:
for o in self.content:
yield o
except GeneratorExit:
return
没有记录(当然)因为__exit__ 是用exc_type=None 调用的。
- 为什么我在
__exit__中看到的是GeneratorExit而不是ValueError? - 我该怎么做才能获得所需的行为,即
ValueErrorin__exit__?
【问题讨论】:
-
所提供代码的具体目标是什么?您是否试图提供一个也是迭代器的上下文管理器?您为什么要尝试将实例本身用作上下文管理器来获取迭代器?如果您只进行迭代,则不需要在
__iter__内调用with self:,因为根据类的定义,它已经在其中。 -
@metatoaster:这是一个最小的例子——实际上
__enter__和__exit__都做了一些重要的事情。 -
好的,要正确地做到这一点,你真的想把这两个东西(上下文管理器和迭代器)分成两个独立的东西,因为上下文管理器也是一个可以使事情混乱的生成器。但是,如果您能够指定如何使用此类,则可以做一些事情。
-
@metatoaster:实际上,为了简洁起见,我将两个类(context 和 iter)合并为一个。关键是我不明白为什么我看到的是
GeneratorExit而不是ValueError。 -
虽然您似乎可以通过检查
__exit__中的当前堆栈来找到违规行,但this related 可能会有所帮助。
标签: python python-3.x iterator generator