首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python函数的适当类型注解

Python函数的适当类型注解
EN

Stack Overflow用户
提问于 2016-07-17 09:13:46
回答 3查看 29K关注 0票数 80

在读了伊莱·本德斯基的文章如何通过Python协同实现状态机之后,我想.

  • 参见在Python3下运行的示例
  • ,并为生成器添加适当的类型注释。

我成功地完成了第一部分(但是没有使用async def__s或yield from__s,我基本上只是移植了代码--所以这里的任何改进都是最受欢迎的)。

但是,我需要一些帮助来处理coroutines的类型注释:

代码语言:javascript
复制
#!/usr/bin/env python3

from typing import Callable, Generator

def unwrap_protocol(header: int=0x61,
                    footer: int=0x62,
                    dle: int=0xAB,
                    after_dle_func: Callable[[int], int]=lambda x: x,
                    target: Generator=None) -> Generator:
    """ Simplified protocol unwrapping co-routine."""
    #
    # Outer loop looking for a frame header
    #
    while True:
        byte = (yield)
        frame = []  # type: List[int]

        if byte == header:
            #
            # Capture the full frame
            #
            while True:
                byte = (yield)
                if byte == footer:
                    target.send(frame)
                    break
                elif byte == dle:
                    byte = (yield)
                    frame.append(after_dle_func(byte))
                else:
                    frame.append(byte)


def frame_receiver() -> Generator:
    """ A simple co-routine "sink" for receiving full frames."""
    while True:
        frame = (yield)
        print('Got frame:', ''.join('%02x' % x for x in frame))

bytestream = bytes(
    bytearray((0x70, 0x24,
               0x61, 0x99, 0xAF, 0xD1, 0x62,
               0x56, 0x62,
               0x61, 0xAB, 0xAB, 0x14, 0x62,
               0x7)))

frame_consumer = frame_receiver()
next(frame_consumer)  # Get to the yield

unwrapper = unwrap_protocol(target=frame_consumer)
next(unwrapper)  # Get to the yield

for byte in bytestream:
    unwrapper.send(byte)

运转正常..。

代码语言:javascript
复制
$ ./decoder.py 
Got frame: 99afd1
Got frame: ab14

...and还进行了类型选择:

代码语言:javascript
复制
$ mypy --disallow-untyped-defs decoder.py 
$

但是,我非常肯定我可以做得更好,而不仅仅是在类型规范中使用Generator基类(就像我对Callable那样)。我知道它需要3种类型的参数(Generator[A,B,C]),但我不知道在这里如何确切地指定它们。

任何最受欢迎的帮助。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-07-17 16:25:17

我自己想出了答案。

我搜索了一下,但是没有在Generator中找到关于Python3.5.2的正式输入文档的3种类型参数的文档--除了提到.

代码语言:javascript
复制
class typing.Generator(Iterator[T_co], Generic[T_co, T_contra, V_co])

幸运的是,原始PEP484 (这一切的开始)更有帮助:

“生成器函数的返回类型可以由泛型类型Generatoryield_type、send_type、typing.py模块提供的return_type注释:

代码语言:javascript
复制
def echo_round() -> Generator[int, float, str]:
    res = yield
    while res:
        res = yield round(res)
    return 'OK'

基于此,我能够注释我的生成器,并看到mypy确认了我的任务:

代码语言:javascript
复制
from typing import Callable, Generator

# A protocol decoder:
#
# - yields Nothing
# - expects ints to be `send` in his yield waits
# - and doesn't return anything.
ProtocolDecodingCoroutine = Generator[None, int, None]

# A frame consumer (passed as an argument to a protocol decoder):
#
# - yields Nothing
# - expects List[int] to be `send` in his waiting yields
# - and doesn't return anything.
FrameConsumerCoroutine = Generator[None, List[int], None]


def unwrap_protocol(header: int=0x61,
                    footer: int=0x62,
                    dle :int=0xAB,
                    after_dle_func: Callable[[int], int]=lambda x: x,
                    target: FrameConsumerCoroutine=None) -> ProtocolDecodingCoroutine:
    ...

def frame_receiver() -> FrameConsumerCoroutine:
    ...

我测试了我的作业,例如交换类型的顺序-然后,正如预期的,mypy抱怨并要求适当的(如上面所示)。

完整的代码从这里可以到达

我将把这个问题保留几天,以防有人想加入--特别是在使用Python3.5 (async def等)的新协同器风格方面--我很想知道它们在这里的确切用法。

票数 84
EN

Stack Overflow用户

发布于 2019-09-13 03:06:57

如果您有一个使用yield的简单函数,那么您可以使用Iterator类型来注释其结果,而不是Generator

代码语言:javascript
复制
from typing import Iterator

def count_up() -> Iterator[int]:
    for x in range(10):
        yield x
票数 54
EN

Stack Overflow用户

发布于 2021-03-15 10:02:49

在撰写本文时,Python文档还显式地提到了如何处理异步案例(在已接受的答案中已经提到了非异步示例)。

引用的理由如下:

代码语言:javascript
复制
async def echo_round() -> AsyncGenerator[int, float]:
    sent = yield 0
    while sent >= 0.0:
        rounded = await round(sent)
        sent = yield rounded

(第一个参数是产率类型,第二个参数是发送类型)或简单情况下(发送类型为空)。

代码语言:javascript
复制
async def infinite_stream(start: int) -> AsyncIterator[int]:
    while True:
        yield start
        start = await increment(start)
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38419654

复制
相关文章

相似问题

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