在读了伊莱·本德斯基的文章如何通过Python协同实现状态机之后,我想.
我成功地完成了第一部分(但是没有使用async def__s或yield from__s,我基本上只是移植了代码--所以这里的任何改进都是最受欢迎的)。
但是,我需要一些帮助来处理coroutines的类型注释:
#!/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)运转正常..。
$ ./decoder.py
Got frame: 99afd1
Got frame: ab14...and还进行了类型选择:
$ mypy --disallow-untyped-defs decoder.py
$但是,我非常肯定我可以做得更好,而不仅仅是在类型规范中使用Generator基类(就像我对Callable那样)。我知道它需要3种类型的参数(Generator[A,B,C]),但我不知道在这里如何确切地指定它们。
任何最受欢迎的帮助。
发布于 2016-07-17 16:25:17
我自己想出了答案。
我搜索了一下,但是没有在Generator中找到关于Python3.5.2的正式输入文档的3种类型参数的文档--除了提到.
class typing.Generator(Iterator[T_co], Generic[T_co, T_contra, V_co])幸运的是,原始PEP484 (这一切的开始)更有帮助:
“生成器函数的返回类型可以由泛型类型Generatoryield_type、send_type、typing.py模块提供的return_type注释:
def echo_round() -> Generator[int, float, str]:
res = yield
while res:
res = yield round(res)
return 'OK'基于此,我能够注释我的生成器,并看到mypy确认了我的任务:
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等)的新协同器风格方面--我很想知道它们在这里的确切用法。
发布于 2019-09-13 03:06:57
如果您有一个使用yield的简单函数,那么您可以使用Iterator类型来注释其结果,而不是Generator。
from typing import Iterator
def count_up() -> Iterator[int]:
for x in range(10):
yield x发布于 2021-03-15 10:02:49
在撰写本文时,Python文档还显式地提到了如何处理异步案例(在已接受的答案中已经提到了非异步示例)。
引用的理由如下:
async def echo_round() -> AsyncGenerator[int, float]:
sent = yield 0
while sent >= 0.0:
rounded = await round(sent)
sent = yield rounded(第一个参数是产率类型,第二个参数是发送类型)或简单情况下(发送类型为空)。
async def infinite_stream(start: int) -> AsyncIterator[int]:
while True:
yield start
start = await increment(start)https://stackoverflow.com/questions/38419654
复制相似问题