首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >用来表示可重复多次迭代的Iterable的pythonic方法是什么?

用来表示可重复多次迭代的Iterable的pythonic方法是什么?
EN

Stack Overflow用户
提问于 2020-07-26 19:24:54
回答 2查看 775关注 0票数 11

我想获得您关于用python以类型提示表示以下函数的最python方式的建议:

我希望将函数公开为接受输入参数并返回输出的库的一部分。输入参数的合同应该是:

我的函数可以迭代它,reference)

  • it's,

  • ,如果我的函数保持对输入的引用(例如,返回一个保持该 ok的对象来迭代输入不止一次)

一个例子可能是一个函数,它接受一个URL序列,然后向这些URL发出请求,可能会使用一些重试逻辑,因此我必须多次迭代原始序列。但我的问题比这个例子更笼统。

乍一看,一个合适的签名是:

代码语言:javascript
代码运行次数:0
运行
复制
from typing import Iterable

def do_sth(input: Iterable[str]) -> SomeResult:
  ...

然而,这违反了第三个需求,因为在python中,不能保证您可以多次迭代一个Iterable,例如,因为迭代器和生成器本身就是可迭代的。

另一种尝试可能是:

代码语言:javascript
代码运行次数:0
运行
复制
from typing import Sequence

def do_sth(input: Sequence[str]) -> SomeResult:
  ...

但是,Sequence契约超出了我的函数所需的范围,因为它包括索引访问和长度知识。

我想到的一个解决方案是使用Iterable签名,然后在内部复制输入。但是,如果源序列很大,这似乎会带来潜在的内存问题。

对此是否有解决方案,即python是否知道Iterable的概念,即每次返回一个新的迭代器?

EN

回答 2

Stack Overflow用户

发布于 2022-03-29 21:11:10

我可以想出两种自然的方法来表达这一点。

首先是使用Iterable[str],并在文档中提到,不应该使用IteratorGenerator对象,因为您可能有多个对__iter__的调用。Iterable的全部要点是,您可以在它上获得一个迭代器,而且可以说,首先使Iterator支持Iterable是一个错误。它不是完美的,但很简单,这通常更多的是“琵琶”,而不是一个技术上更正确的注释,这是非常复杂的。

您可以添加一些运行时检查,这些检查将提醒用户,如果他们传递了错误的东西,就会出现问题:

代码语言:javascript
代码运行次数:0
运行
复制
iter1 = iter(input)
for item in iter1:
    do_something(item)
iter2 = iter(input)
if iter2 is iter1:
    raise ValueError("Must pass an iterable that can be iterated multiple times. Got {input}.")

或者检查是否有Iterator,并使用内存惩罚来处理它:

代码语言:javascript
代码运行次数:0
运行
复制
if isinstance(input, Iterator):
    input = list(input)  # or itertools.tee or whatever
    warn("This may eat up a lot of memory")

另一种选择是使用io.TextIOBase。这可以通过寻求开始重复多次。这取决于您的用例,可能不是很合适。如果输入在概念上是字符序列上的某种块视图,则io流是一个很好的匹配,即使迭代器在技术上不返回文本行。如果它在概念上是一个不连续的字符串序列,那么流就不是一个很好的匹配。

票数 1
EN

Stack Overflow用户

发布于 2022-11-15 00:17:50

您可以使用不接受输入并返回可迭代的函数。在输入提示方面,您将使用Callable

在文档中,如果您不熟悉Callable

需要特定签名的回调函数的

框架可以使用Callable[[Arg1Type, Arg2Type], ReturnType]进行类型提示。

解决方案:

代码语言:javascript
代码运行次数:0
运行
复制
from typing import Callable, Iterable

def do_sth(get_input: Callable[[], Iterable[str]]) -> SomeResult:
    # ...
    pass

def main():
    do_sth(lambda : (str(i) for i in range(10)))

我的函数可以迭代它

代码语言:javascript
代码运行次数:0
运行
复制
def do_sth(get_input: Callable[[], Iterable[str]]) -> SomeResult:
    for item in get_input():
        pass

如果我的函数维护对输入的引用(例如,通过返回保存该引用的对象),这是可以的。

为什么不呢。

代码语言:javascript
代码运行次数:0
运行
复制
def do_sth(get_input: Callable[[], Iterable[str]]) -> SomeResult:
    return dict(reference=get_input)

可以多次迭代输入

代码语言:javascript
代码运行次数:0
运行
复制
def do_sth(get_input: Callable[[], Iterable[str]]) -> SomeResult:
    for i in range(10**82):
        for item in get_input():
            pass
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63104689

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档