从另一个通用Lambda参数推论通用Lambda参数

P D*_*ddy 8 python mypy

考虑以下代码:

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())
)
Run Code Online (Sandbox Code Playgroud)

这段代码可以正常运行,并且可以正常运行,但是,mypy无法推断s第二个lambda 的类型,从而出现错误:

“对象”没有属性“较低”

现在,我唯一的解决方法是强制转换s(可能是更复杂的lambda或类型更复杂的痛苦),或者添加# type: ignore(我宁愿不这样做)。

有更好的解决方法,还是让mypy识别类型的正确方法?

bun*_*nji 2

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

  • 您希望您T TypeVar是通用的,以便producer和consumer参数的类型注释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)
Run Code Online (Sandbox Code Playgroud)

编辑

另一个建议:

由于您无论如何都使用泛型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())
)
Run Code Online (Sandbox Code Playgroud)

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