正确使用生成器打字

问题描述 投票:0回答:3

我正在尝试向返回生成器的方法添加类型。每当我使用指定的返回类型运行该程序时,都会引发 TypeError。

添加引号或删除输入可以修复错误,但这看起来像是黑客。当然有正确的方法来做到这一点。

def inbox_files(self) -> "Generator[RecordsFile]":
    ...

# OR

def inbox_files(self):
    ...
from typing import Generator, List
from .records_file import RecordsFile

Class Marshaller:

    ...

    def inbox_files(self) -> Generator[RecordsFile]:
        return self._search_directory(self._inbox)

    def _search_directory(self, directory: str) -> RecordsFile:
        for item_name in listdir(directory):
            item_path = path.join(item_name, directory)
            if path.isdir(item_path):
                yield from self._search_directory(item_path)
            elif path.isfile(item_path):
                yield RecordsFile(item_path)
            else:
                print(f"[WARN] Unknown item found: {item_path}")

生成以下堆栈跟踪:

Traceback (most recent call last):
  File "./bin/data_marshal", line 8, in <module>
    from src.app import App
  File "./src/app.py", line 9, in <module>
    from .marshaller import Marshaller
  File "./src/marshaller.py", line 9, in <module>
    class Marshaller:
  File "./src/marshaller.py", line 29, in Marshaller
    def inbox_files(self) -> Generator[RecordsFile]:
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/typing.py", line 254, in inner
    return func(*args, **kwds)
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/typing.py", line 630, in __getitem__
    _check_generic(self, params)
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/typing.py", line 208, in _check_generic
    raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};"
TypeError: Too few parameters for typing.Generator; actual 1, expected 3

́\_(ツ)_/́

python python-3.x generator
3个回答
37
投票

您必须显式指定发送类型和返回类型,即使两者都是

None

def inbox_files(self) -> Generator[RecordsFile,None,None]:
    return self._search_directory(self._inbox)

请注意,yield 类型可能是您认为的返回类型。发送类型是您可以传递给生成器的

send
方法的值类型。返回类型是在产生所有可能的值之后可以嵌入由
StopIteration
引发的
next
异常中的值的类型。考虑:

def foo():
    yield 3
    return "hi"

f = foo()

第一次调用

next(f)
将返回3;第二个将提高
StopIteration("hi")
。 )


无法发送或返回的生成器只是一个可迭代对象或迭代器(显然都可以使用)。

def inbox_files(self) -> Iterable[RecordsFile]:  # Or Iterator[RecordsFile]
    return self._search_directory(self._inbox)

_search_directory
本身also返回一个生成器/可迭代对象,而不是
RecordsFile
的实例:

def _search_directory(self, directory: str) -> Iterable[RecordsFile]:

0
投票

如果经常使用

Generator[RecordsFile, None, None]
太麻烦,你可以给一个类型起别名:

from typing import Generator, TypeVar

T = TypeVar('T')
type Gen[T] = Generator[T, None, None]

# now use `Gen[RecordsFile]` as an alias for `Generator[RecordsFile, None, None]`

-1
投票

这个答案很有用,但我很困惑,因为我确信我过去只使用过带有一个参数的 Generator[] 并且它有效。

我追溯到使用“from __future__ import comments”。 在这种情况下似乎只需要一个参数。

© www.soinside.com 2019 - 2024. All rights reserved.