Car*_*ten 8 python api-design type-hinting
我想就最pythonic的方式获得您的建议,以使用类型提示在python中表达以下函数:
我想公开一个函数作为接受输入参数并返回输出的库的一部分。输入参数的契约应该是:
一个例子可能是一个函数,它接受一系列 URL,然后向这些 URL 发出请求,可能带有一些重试逻辑,所以我必须不止一次迭代原始序列。但我的问题不仅仅是这个样本。
乍一看,合适的签名是:
from typing import Iterable
def do_sth(input: Iterable[str]) -> SomeResult:
...
Run Code Online (Sandbox Code Playgroud)
然而,这违反了第三个要求,因为在 python 中不能保证您可以多次迭代一个 Iterable,例如因为迭代器和生成器本身就是可迭代的。
另一种尝试可能是:
from typing import Sequence
def do_sth(input: Sequence[str]) -> SomeResult:
...
Run Code Online (Sandbox Code Playgroud)
但是Sequence合同超出了我的功能要求,因为它包括索引访问和长度知识。
我想到的一个解决方案是使用Iterable签名,然后在内部制作输入的副本。但是如果源序列很大,这似乎会引入潜在的内存问题。
有没有解决方案,即python是否知道Iterable每次都会返回一个新迭代器的概念?
我能想到有两种自然的方式来表示这一点。
第一种是使用Iterable[str], 并在文档中提到,不应使用Iterator和Generator对象,因为您可能会多次调用__iter__. 重点Iterable是您可以在其上获得迭代器,可以说,一开始提供Iterator支持就是一个错误。Iterable它并不完美,但很简单,通常比技术上更正确但非常复杂的注释更“Pythonic”。
您可以添加一些运行时检查,如果用户传递了错误的内容,则会提醒用户存在问题:
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}.")
Run Code Online (Sandbox Code Playgroud)
或者检查你是否有迭代器,并用内存惩罚来处理它:
if isinstance(input, Iterator):
input = list(input) # or itertools.tee or whatever
warn("This may eat up a lot of memory")
Run Code Online (Sandbox Code Playgroud)
另一种选择是使用io.TextIOBase. 这可以通过查找开头来迭代多次。这取决于您的用例,并且可能不太适合。如果从概念上讲,输入是字符序列上的某种分块视图,那么 io 流就很适合,即使迭代器在技术上不返回文本行。如果从概念上讲它是不连续的字符串序列,那么流就不适合。
| 归档时间: |
|
| 查看次数: |
193 次 |
| 最近记录: |