mypy:在没有运行时成本的情况下对类型提出更严格的要求

问题描述 投票:1回答:1

我正在接收来自远程方的消息,这些消息被解码为如下所示的类:

class SomeMessage(MessageType):
    foo: Optional[int]
    bar: Optional[str]
    quux: Optional[AnotherMessageType]

大多数字段始终是可选的。有线消息可能包含也可能不包含。

但是,我的代码事先进行了验证,然后大多假定存在适当的字段。

例如:

def process_all_foos(messages: List[SomeMessage]):
    messages_with_foo = [m for m in messages if m.foo is not None]
    foo_sum = sum(m.foo for m in messages_with_foo)

该代码无法进行类型检查,因为mypy不会保留先前的检查。

是否有可能进行上述代码的类型检查以某种方式>>而不会产生运行时成本?

我的想法是创建一个具有更高要求的协议:

class SomeMessageWithFoo(Protocol):
    foo: int

def convert_foo(m: SomeMessage) -> SomeMessageWithFoo:
    assert m.foo is not None
    return m

# or, ideally:
def process_all_foos(messages: List[SomeMessage]):
    messages_with_foo: List[SomeMessageWithFoo] = [m for m in messages if m.foo is not None]
    foo_sum = sum(m.foo for m in messages_with_foo)

但是,mypy拒绝了:

test.py:16: error: Incompatible return value type (got "SomeMessage", expected "SomeMessageWithFoo")  [return-value]
test.py:16: note: Following member(s) of "SomeMessage" have conflicts:
test.py:16: note:     foo: expected "int", got "Optional[int]"
test.py:20: error: List comprehension has incompatible type List[SomeMessage]; expected List[SomeMessageWithFoo]  [misc]
test.py:20: note: Following member(s) of "SomeMessage" have conflicts:
test.py:20: note:     foo: expected "int", got "Optional[int]"

我考虑使用cast(SomeMessageWithFoo, m),或更可能使用# type: ignore,因为这没有运行时成本。 (我在嵌入式环境中,因此我确实关心cast的函数调用。)但这也让我not

检查该字段。

即,以下错误地进行类型检查:

def convert_foo(m: SomeMessage) -> SomeMessageWithFoo:
    # someone commented this out:
    #assert m.foo is not None
    return cast(SomeMessageWithFoo, m)

是否有一种方法可以完成此过程,从而进行代码类型检查,但实际上仍可以验证需求?

我正在接收来自远程方的消息,这些消息被解码成如下所示的类:class SomeMessage(MessageType):foo:可选[int]栏:可选[str]队列:可选[...

python mypy python-typing
1个回答
0
投票

我不明白。显而易见的解决方案不是a)使您的代码更快,因为您只执行一次迭代而不是两次,并且b)修复了类型检查:

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