关于python:如何处理耗尽的迭代器?

How to handle an exhausted iterator?

在搜索python文档时,我发现了在zip()函数中构建的pythons的等效python实现。

不是捕获一个StopIteration异常,该异常表示迭代器没有生成其他项,而是使用if语句检查返回的默认值next()是否等于object()(sentinel并停止生成器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def zip(*iterables):
    # zip('ABCD', 'xy') --> Ax By
    sentinel = object()
    iterators = [iter(it) for it in iterables]
    while iterators:
        result = []
        for it in iterators:
            elem = next(it, sentinel)

            if elem is sentinel:
                return

            result.append(elem)
        yield tuple(result)

我想知道异常捕获和python文档使用的if语句之间是否有区别?

或者更好,正如@hiro主人公指出的那样:
在python中使用try语句考虑EAFP(比许可更容易请求宽恕)有什么问题?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def zip(*iterables):
    # zip('ABCD', 'xy') --> Ax By
    iterators = [iter(it) for it in iterables]
    while iterators:
        result = []
        for it in iterators:

            try:
                elem = next(it)
            except StopIteration:
                return

            result.append(elem)
        yield tuple(result)

同样,正如Stoyan Dekov提到的,"如果没有引发异常,尝试/例外块是非常有效的。实际上捕获异常是昂贵的。"(有关详细信息,请参阅文档)
但异常只会发生一次,即在迭代器用完后立即发生。那么在这种情况下,异常处理是更好的解决方案吗?


你的意思是和这个相反?

1
2
3
4
5
6
7
8
9
10
11
12
13
def zip2(*iterables):
    # zip('ABCD', 'xy') --> Ax By
    iterators = [iter(it) for it in iterables]
    while iterators:
        result = []
        for it in iterators:
            try:
                elem = next(it)
            except StopIteration:
                return

            result.append(elem)
        yield tuple(result)

有趣的问题…我更喜欢这个替代版本——尤其是考虑到EAFP(请求宽恕比许可更容易)。

即使try/except比if语句慢;这只会发生一次-只要第一个迭代器用完。

值得注意的是,这不是Python中的实际实现;只是一个等价于实际实现的实现。

根据评论更新:

注意,PEP 479建议发电机向return发出信号,而不是向StopIteration发出信号。


通常,在任何编程语言中,引发异常都被认为是一种昂贵的操作。有很多网站可以阅读这是为什么,我不打算详细讨论它涉及到什么。

来自python文档。

A try/except block is extremely efficient if no exceptions are raised. Actually catching an exception is expensive.

使用if/elsetry/catch都有其优缺点。

  • 例如,try/catch主要用于异常很少发生的情况(例如,代码在几乎所有情况下都会成功)。
  • 在您的示例中,您知道循环在每次调用时都会抛出一个异常,这使得使用try/catch非常低效。


当您在文档中看到等效的python代码时,这样的代码的目标是易于理解。if很容易理解,而try/except是一个更高层次的结构。

功能上没有区别。从性能上讲,可能有一个小的,但可能微不足道的差异。

就实际的编码过程而言,不同的人用不同的方式思考,所以使用对您来说更合理的方法。当lbyl和eafp真正起作用的时候,就是一个竞争条件可以存在的时候——这里没有这样的条件。