Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在一系列上下文管理器上友好地使用Python iterable_Python_Python 3.x_Iterator_Contextmanager - Fatal编程技术网

在一系列上下文管理器上友好地使用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来实现这一点。所以我敢打赌,除了用硬编码类型重新引用上述异常外,没有办法合并这两个结构。我得多想想。