"从迭代中获得"vs"返回iter(可迭代)"

Pet*_*erE 21 python iterable python-3.x yield-from

在包装(内部)迭代器时,通常必须将__iter__方法重新路由到底层的iterable.请考虑以下示例:

class FancyNewClass(collections.Iterable):
    def __init__(self):
        self._internal_iterable = [1,2,3,4,5]

    # ...

    # variant A
    def __iter__(self):
        return iter(self._internal_iterable)

    # variant B
    def __iter__(self):
        yield from self._internal_iterable
Run Code Online (Sandbox Code Playgroud)

变体A和B之间是否有任何显着差异?Variant A返回iter()已从内部iterable中查询过的迭代器对象.变量B返回一个生成器对象,该对象返回内部可迭代的值.出于某种原因,是其中一种还是其他的?在collections.abcyield from版本中使用.该return iter()变种是,我已经使用到现在的格局.

eca*_*mur 15

唯一显着的区别是当从迭代中引发异常时会发生什么.使用return iter()你的FancyNewClass意志不会出现在异常回溯上,而yield from它会出现.虽然可能存在要隐藏包装器的情况,但尽可能多地获取有关回溯的信息通常是件好事.

其他差异:

  • return iter必须iter从全局变量中加载名称- 这可能很慢(虽然不太可能显着影响性能)并且可能会被搞乱(尽管任何覆盖像这样的全局变量的人都应该得到它们).

  • 随着yield from您可以插入其他的yield之前和之后的表达式(虽然你同样可以使用itertools.chain).

  • 如上所述,yield from表单会丢弃任何生成器返回值(即raise StopException(value),您可以通过编写来修复此问题return (yield from iterator).

这是一个测试,比较两种方法的反汇编,并显示异常追溯:http://ideone.com/1YVcSe

使用return iter():

  3           0 LOAD_GLOBAL              0 (iter)
              3 LOAD_FAST                0 (it)
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 RETURN_VALUE
Traceback (most recent call last):
  File "./prog.py", line 12, in test
  File "./prog.py", line 10, in i
RuntimeError
Run Code Online (Sandbox Code Playgroud)

使用return (yield from):

  5           0 LOAD_FAST                0 (it)
              3 GET_ITER
              4 LOAD_CONST               0 (None)
              7 YIELD_FROM
              8 RETURN_VALUE
Traceback (most recent call last):
  File "./prog.py", line 12, in test
  File "./prog.py", line 5, in bar
  File "./prog.py", line 10, in i
RuntimeError
Run Code Online (Sandbox Code Playgroud)