Python3 中是否有内置的 `take(iterable, n)` 函数?
Is there a built-in `take(iterable, n)` function in Python3?
我只是在一些嵌套生成器中滥用 StopIteration
(使用 CPython 3.6.9),没有启用 PEP 479(from __future__ import generator_stop
),并且有一些糟糕的黑客代码使用 next(iter(iterable))
过早地发出停止信号。
虽然 PEP 479 会捕获 StopIteration
从生成器中冒出来的问题,但我想我仍然会 运行 进入嵌套的 for 循环。
现在,我将用以下内容替换 next(iter(...))
的所有用法:
def take(iterable, *, n):
"""
Robustly gets the first n items from an iterable and returns them as a
list.
You should always use this function in lieu of `next(iter(...))`! e.g.
instead of:
my_first = next(iter(container))
you should instead do:
my_first, = take(container, n=1)
Throws RuntimeError if the iterable cannot yield n items.
"""
iterator = iter(iterable)
out = []
for _ in range(n):
try:
out.append(next(iterator))
except StopIteration:
raise RuntimeError("Premature StopIteration encountered!")
return out
我的问题是:Python 的标准库中是否已经有这样的函数?
我在 itertools
和 builtins
中检查了 python.org
的最新文档(3.9),我能看到的最接近的东西是 takewhile
,但是嗯那。我也可以转换为 list
或任何其他可索引容器,但我想避免为了访问第一件事而需要遍历所有内容。
itertools.islice
这样做(以及更多),如果没有生成足够的元素,则不会转换为列表或出错。
您可以根据这个干净地编写您的函数:
def take(iterable, *, n):
li = list(itertools.islice(iterable, n))
if len(li) != n:
raise RuntimeError("too short iterable for take")
return li
我只是在一些嵌套生成器中滥用 StopIteration
(使用 CPython 3.6.9),没有启用 PEP 479(from __future__ import generator_stop
),并且有一些糟糕的黑客代码使用 next(iter(iterable))
过早地发出停止信号。
虽然 PEP 479 会捕获 StopIteration
从生成器中冒出来的问题,但我想我仍然会 运行 进入嵌套的 for 循环。
现在,我将用以下内容替换 next(iter(...))
的所有用法:
def take(iterable, *, n):
"""
Robustly gets the first n items from an iterable and returns them as a
list.
You should always use this function in lieu of `next(iter(...))`! e.g.
instead of:
my_first = next(iter(container))
you should instead do:
my_first, = take(container, n=1)
Throws RuntimeError if the iterable cannot yield n items.
"""
iterator = iter(iterable)
out = []
for _ in range(n):
try:
out.append(next(iterator))
except StopIteration:
raise RuntimeError("Premature StopIteration encountered!")
return out
我的问题是:Python 的标准库中是否已经有这样的函数?
我在 itertools
和 builtins
中检查了 python.org
的最新文档(3.9),我能看到的最接近的东西是 takewhile
,但是嗯那。我也可以转换为 list
或任何其他可索引容器,但我想避免为了访问第一件事而需要遍历所有内容。
itertools.islice
这样做(以及更多),如果没有生成足够的元素,则不会转换为列表或出错。
您可以根据这个干净地编写您的函数:
def take(iterable, *, n):
li = list(itertools.islice(iterable, n))
if len(li) != n:
raise RuntimeError("too short iterable for take")
return li