首页 > 解决方案 > 从另一个泛型 lambda 的参数推断泛型 lambda 参数

问题描述

考虑以下代码:

from typing import Callable, TypeVar

T = TypeVar('T')

def middle_man(
    producer: Callable[[], T],
    consumer: Callable[[T], None]
) -> None:
    consumer(producer())

middle_man(
    lambda: "HELLO",
    lambda s: print(s.lower())
)

此代码运行没有错误并且按预期工作,但是,mypy 无法推断s第二个 lambda 中的类型,给出错误:

“object”没有属性“lower”`

现在,我唯一的解决方法是 cast s,这在更复杂的 lambda 或更复杂的类型中可能会很痛苦,或者 add # type: ignore,我不想这样做。

有没有更好的解决方法,或者让 mypy 识别类型的正确方法?

标签: pythonmypy

解决方案


在我看来,您在这里有两个相互矛盾的问题:

  • 你希望你T TypeVar是通用的,以便producerconsumer参数的类型注释middle_man可以灵活
  • 您希望特定调用的类型注释middle_man足够具体,以mypy识别您正在使用str类型调用它

为了实现这一点,我将middle_man通过首先将参数存储为变量来注释特定调用的参数:

from typing import Callable, TypeVar

T = TypeVar('T')

def middle_man(
    producer: Callable[[], T],
    consumer: Callable[[T], None]
) -> None:
    consumer(producer())

producer: Callable[[], str] = lambda: "HELLO"
consumer: Callable[[str], None] = lambda s: print(s.lower())

middle_man(producer, consumer)

编辑

另一个建议:

由于无论如何您都在使用泛型TypeVar,因此您可以将其替换为Any类型而不会丢失类型信息,并且mypy不会引发错误,因为它会跳过对types的静态类型检查Any

from typing import Callable, Any

def middle_man(
    producer: Callable[[], Any],
    consumer: Callable[[Any], None]
) -> None:
    consumer(producer())

middle_man(
    lambda: "HELLO",
    lambda s: print(s.lower())
)

我知道这个解决方案不是很令人满意,因为它基本上违背了mypy用于静态类型检查的目的,但除非你想用一个方法将你的上限限制TypeVar为一个类,lower否则这可能是你最好的选择。


推荐阅读