Python3中是否有内置的`takeiterable,n`函数?

问题描述

我只是在一些嵌套生成器中滥用stopiteration(使用cpython 3.6.9),没有启用PEP 479from __future__ import generator_stop),并且有一些糟糕的hacky代码,使用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的stdlib中已经有这样的函数吗?

我在python.orgitertools中查看了builtins的最新文档(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