【问题标题】:Proper use Generator typing正确使用生成器类型
【发布时间】:2019-12-13 05:57:11
【问题描述】:

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

添加引号或删除输入可修复错误,但这似乎是 hack。这样做肯定有正确的方法。

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


    【解决方案1】:

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

    我追溯到使用“来自 __future__ 导入注释”。在这种情况下,似乎只需要一个参数。

    【讨论】:

    • 嘿丹尼斯!欢迎来到堆栈溢出。您会注意到您可以直接评论此类内容的答案。 Stack Overflow 不使用论坛类型的模型,因此请仅使用答案来提交问题的解决方案。
    • 哦,是的,我就是这么想的。但是输入回复然后创建新帐户,它会将我重定向回来,但回复在错误的位置。嗯,下次再来! :)
    【解决方案2】:

    你必须明确指定发送类型和返回类型,即使两者都是None

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

    请注意,yield 类型是您可能认为的返回类型。发送类型是您可以传递给生成器的send 方法的值的类型。返回类型是可以嵌入到next 引发的StopIteration 异常中的值的类型,在所有可能的值都已经产生之后。考虑:

    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 本身返回一个生成器/可迭代对象,而不是RecordsFile 的实例:

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

    【讨论】:

    • 感谢您的友好和清晰的解释。 Python 的生成器比我知道的要多。我必须查看文档,以便充分利用它们。
    • 能否请您提供指向Generator[T1, T2, T3] 文档的指针?
    • 为后代回答自己,似乎记录在这里:docs.python.org/3/library/typing.html#typing.Generator
    猜你喜欢
    • 2022-01-20
    • 2021-01-19
    • 2013-04-18
    • 1970-01-01
    • 2014-11-13
    • 2015-03-08
    • 2012-08-01
    • 1970-01-01
    • 2019-08-25
    相关资源
    最近更新 更多