"yield from iterable" 对比 "return iter(iterable)"
"yield from iterable" vs "return iter(iterable)"
当包装一个(内部)迭代器时,通常必须将 __iter__
方法重新路由到底层的可迭代对象。考虑以下示例:
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
变体 A 和 B 之间有什么显着差异吗?
Variant A returns 已通过 iter()
从内部可迭代查询的迭代器对象。变体 B returns 一个生成器对象,returns 来自内部可迭代的值。由于某种原因,一个或另一个更可取吗?在 collections.abc
中使用 yield from
版本。 return iter()
变体是我到目前为止使用的模式。
唯一的显着区别是从可迭代对象中引发异常时发生的情况。使用 return iter()
你的 FancyNewClass
不会出现在异常回溯中,而使用 yield from
它会。拥有尽可能多的关于回溯的信息通常是一件好事,尽管在某些情况下您可能想要隐藏包装器。
其他差异:
return iter
必须从全局加载名称 iter
- 这可能很慢(尽管不太可能显着影响性能)并且可能会被弄乱(尽管任何人覆盖像这样的全局变量值得他们得到。
使用 yield from
你可以在前后插入其他 yield
表达式(尽管你同样可以使用 itertools.chain
)。
如前所述,yield from
形式会丢弃任何生成器 return 值(即 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
使用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
当包装一个(内部)迭代器时,通常必须将 __iter__
方法重新路由到底层的可迭代对象。考虑以下示例:
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
变体 A 和 B 之间有什么显着差异吗?
Variant A returns 已通过 iter()
从内部可迭代查询的迭代器对象。变体 B returns 一个生成器对象,returns 来自内部可迭代的值。由于某种原因,一个或另一个更可取吗?在 collections.abc
中使用 yield from
版本。 return iter()
变体是我到目前为止使用的模式。
唯一的显着区别是从可迭代对象中引发异常时发生的情况。使用 return iter()
你的 FancyNewClass
不会出现在异常回溯中,而使用 yield from
它会。拥有尽可能多的关于回溯的信息通常是一件好事,尽管在某些情况下您可能想要隐藏包装器。
其他差异:
return iter
必须从全局加载名称iter
- 这可能很慢(尽管不太可能显着影响性能)并且可能会被弄乱(尽管任何人覆盖像这样的全局变量值得他们得到。使用
yield from
你可以在前后插入其他yield
表达式(尽管你同样可以使用itertools.chain
)。如前所述,
yield from
形式会丢弃任何生成器 return 值(即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
使用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