如何为一个分块器函数添加类型注解?

huangapple go评论140阅读模式
英文:

How to type annotate a chunker function?

问题

以下是您要翻译的代码部分:

from typing import Iterator, List, Any, TypeVar

T = TypeVar('T')

def chunker(seq: Iterator[T], size: int) -> Iterator[List[T]]:
    for i in seq:
        yield []

for i in chunker([1, 2, 3, 4], 5):
    pass

请注意,代码部分已经被翻译成中文。如果您需要进一步的帮助,请随时提问。

英文:

I try the following:

from typing import Iterator, List, Any, TypeVar
T = TypeVar('T')
def chunker(seq: Iterator[T], size: int) -> Iterator[List[T]]:
    for i in seq:
        yield []
for i in chunker([1, 2, 3, 4], 5):
    pass

However, pyright tells me that:

  test.py:5:18 - error: Argument of type "list[int]" cannot be assigned to parameter "seq" of type "Iterator[T@chunker]" in function "chunker"
    "list[int]" is incompatible with protocol "Iterator[T@chunker]"
      "__next__" is not present (reportGeneralTypeIssues)
1 error, 0 warnings, 0 informations 

How should I annotate a function that takes something that you can for i in seq it?

I tried searching on stack and google, but I guess like my google-fu is not good enough. I could use Union[Iterator[T], List[T]] but I think there should be something better?

答案1

得分: 2

以下是翻译好的部分:

迭代器是具有状态的对象,它在迭代过程中记住了自己的位置。它具有一个 __next__ 方法,该方法返回迭代中的下一个值,更新状态以指向下一个值,并通过引发 StopIteration 信号来表示完成。

正如您所见,列表没有 __next__ 方法:

>>> [1,2,3].__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__next__'

相反,您真正想要的是一个可迭代对象。可迭代对象包括:

  • 任何可以进行循环遍历的东西(例如,您可以循环遍历字符串或文件)
  • 可以出现在 for 循环右侧的任何东西:for x in iterable: ...
  • 您可以使用 iter() 调用的任何东西,它将返回一个迭代器:iter(obj)
  • 定义了返回新迭代器的 __iter__ 的对象

列表确实是一个可迭代对象:

>>> [1,2,3].__iter__()
<list_iterator object at 0x103e68310>

更多信息可以在此问题中找到:https://stackoverflow.com/q/9884132/5296106

因此,您应该将示例重写为:

from collections.abc import Generator, Iterable
from typing import Any, TypeVar

T = TypeVar('T')
def chunker(seq: Iterable[T], size: int) -> Generator[list[T], None, None]:
    for i in seq:
        yield []
for i in chunker([1, 2, 3, 4], 5):
    pass

请注意,自Python版本3.9起,typing.Iterable 已弃用。更多详细信息可在此处找到。另外,typing.Listlist 的已弃用别名(更多详细信息请见此处)。

更简单的方法是使用 Iterator 而不是 Generator(每个生成器都是迭代器!!):

from collections.abc import Iterable, Iterator
from typing import Any, TypeVar

T = TypeVar('T')
def chunker(seq: Iterable[T], size: int) -> Iterator[list[T]]:
    for i in seq:
        yield []
for i in chunker([1, 2, 3, 4], 5):
    pass
英文:

An iterator is an object with state that remembers where it is during iteration. It has a __next__ method that returns the next value in the iteration, updates the state to point at the next value and signals when it is done by raising StopIteration.

As you can see, a list does not have a __next__ method:

>>> [1,2,3].__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__next__'

Instead, what you really want here is an iterable. An iterable is:

  • anything that can be looped over (i.e. you can loop over a string or file)
  • anything that can appear on the right-side of a for-loop: for x in iterable: ...
  • anything you can call with iter() that will return an iterator: iter(obj)
  • an object that defines __iter__ that returns a fresh iterator

A list is indeed an iterable:

>>> [1,2,3].__iter__()
<list_iterator object at 0x103e68310>

More info can be found in this question: https://stackoverflow.com/q/9884132/5296106

So you should rewrite your example as:

from collections.abc import Generator, Iterable
from typing import Any, TypeVar

T = TypeVar('T')
def chunker(seq: Iterable[T], size: int) -> Generator[list[T], None, None]:
    for i in seq:
        yield []
for i in chunker([1, 2, 3, 4], 5):
    pass

Notice that since Python version 3.9, typing.Iterable is deprecated. More details can be found here. Also, typing.List is a deprecated alias of list (more details here).

A simpler way is to use Iterator instead of Generator (every generator is an iterator!!):

from collections.abc import Iterable, Iterator
from typing import Any, TypeVar

T = TypeVar('T')
def chunker(seq: Iterable[T], size: int) -> Iterator[list[T]]:
    for i in seq:
        yield []
for i in chunker([1, 2, 3, 4], 5):
    pass

huangapple
  • 本文由 发表于 2023年6月29日 18:09:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76580063.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定