在一系列上下文管理器上友好地使用Python iterable
我正在编写一个小型库,它试图为分派作业提供一个持久队列。我的持久性代码提供了一种迭代挂起的工作描述的方法;我还想保证分派的作业最终会被标记为已完成或失败 为此,我首先实现了它,以便我的用户能够:在一系列上下文管理器上友好地使用Python iterable,python,python-3.x,iterator,contextmanager,Python,Python 3.x,Iterator,Contextmanager,我正在编写一个小型库,它试图为分派作业提供一个持久队列。我的持久性代码提供了一种迭代挂起的工作描述的方法;我还想保证分派的作业最终会被标记为已完成或失败 为此,我首先实现了它,以便我的用户能够: for c in some_iterator_object: with c as x: ... 我不喜欢这个解决方案有几个原因。首先,我想从我的队列中获取一个作业描述,作为一个操作(如果队列为空,则会失败),因此通过迭代器的\uuuuuuuuuuuuuuuuuuuuuuu方法进行获取,并在
for c in some_iterator_object:
with c as x:
...
我不喜欢这个解决方案有几个原因。首先,我想从我的队列中获取一个作业描述,作为一个操作(如果队列为空,则会失败),因此通过迭代器的\uuuuuuuuuuuuuuuuuuuuuuu
方法进行获取,并在上下文管理器的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu退出中进行释放
为了确保调用上下文管理器,my\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
返回一个不能直接替换该
有没有办法把这两条语句合并成一条?理想情况下,我希望让用户这样做
for x in some_iterator_object:
...
同时能够截获由for块的内容引发的异常
EDIT:我通过实验发现,如果我让一个未完成的生成器被垃圾收集,yield语句将引发一个内部异常,因此我可以编写一些粗糙的东西,比如
try:
...
success = False
yield val
success = True
...
finally:
if success:
...
但如果我理解正确,这取决于垃圾收集器的运行,这似乎是一个我不应该真正触及的内部机制。如果您希望上下文管理器在迭代器返回时自动输入,您可以编写自己的迭代器类,如下所示:
class ContextManagersIterator:
def __init__(self, it):
self._it = iter(it)
self._last = None
def __iter__(self):
return self
def __next__(self):
self.__exit__(None, None, None)
item = next(self._it)
item.__enter__()
self._last = item
return item
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
last = self._last
if last is not None:
self._last = None
return last.__exit__(exc_type, exc_value, exc_traceback)
用法示例:
from contextlib import contextmanager
@contextmanager
def my_context_manager(name):
print('enter', name)
try:
yield
finally:
print('exit', name)
sequence = [
my_context_manager('x'),
my_context_manager('y'),
my_context_manager('z'),
]
with ContextManagersIterator(sequence) as it:
for item in it:
print(' work')
# Output:
# enter x
# work
# exit x
# enter y
# work
# exit y
# enter z
# work
# exit z
这个ContextManagersIterator
类负责在返回值之前对其值调用\uuuuuu\uuuuu
<代码>\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
在返回另一个值之前调用(如果一切顺利)或者在循环中引发异常时调用。谢谢,但从可用性的角度。无论如何,我接受这个答案,因为我意识到我是在要求不可能的事情:我还需要能够在主体内部捕获特定的异常并让循环继续,我通过在for循环内部但在with构造外部插入try/catch来实现这一点。所以我敢打赌,除了用硬编码类型重新引用上述异常外,没有办法合并这两个结构。我得多想想。