【问题标题】:Is there a built-in `take(iterable, n)` function in Python3?Python3 中是否有内置的 `take(iterable, n)` 函数?
【发布时间】:2021-02-17 10:19:54
【问题描述】:

我刚刚在一些嵌套生成器中滥用StopIteration(使用CPython 3.6.9),没有启用PEP 479from __future__ import generator_stop),并且有一些过早使用next(iter(iterable))的糟糕的hacky代码示意停止。

虽然 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 的 stdlib 中?

我查看了itertoolsbuiltins 中的python.orgs 最新文档(适用于3.9),我能看到的最接近的是takewhile,但我就这样。我也可以转换为 list 或任何其他可索引容器,但我想避免为了访问第一件事而需要遍历所有内容。

【问题讨论】:

  • islice 也许?
  • 你在找itertools.islice
  • 哦,是的!看起来就是这样-谢谢!!!

标签: python generator python-3.6 stopiteration


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2010-11-07
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-10
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多