如何在赋值时保持类型提示尽管有变量类型注解

1 投票
1 回答
95 浏览
提问于 2025-04-14 17:39

我正在写一个叫做 Lazy 的类,它的功能类似于 partial,但是多了一些额外的功能。这个类的目的是通过将对象包裹在 Lazy 类中来预先初始化一个对象,然后通过调用 to_eager 来完成初始化,用户可以在这个过程中提供一些额外的参数。现在的问题是,在IDE中如何保留类型提示。

下面是代码

from typing import Callable, Generic, ParamSpec, Type, TypeVar


T = TypeVar("T")
P = ParamSpec("P")


class Lazy(Generic[T, P]):  # Any makes it ok to asign to any other type

    def __init__(
        self, cls: Type[T] | Callable[P, T], *args: P.args, **kwargs: P.kwargs
    ):
        self.cls = cls
        self.args = args
        self.kwargs = kwargs

    def to_eager(self, *args: P.args, **kwargs: P.kwargs) -> T:
        assert not args
        kwg = {**self.kwargs, **kwargs}
        return self.cls(*self.args, **kwg)


class SomeClass:
    def __init__(self, y: int = 1):
        self.y = y


l = Lazy(SomeClass, y=5)
l.to_eager()  # here VSCode hints me with (y: int -> 1)

当我尝试调用 to_eager() 时,我能看到关于原始类可能的参数的提示。

在这里输入图片描述

现在的问题是,如果这和变量类型赋值结合在一起会出现什么情况

l: Lazy = Lazy(SomeClass, y=5)
l.to_eager()  # type hint is gone, I get (... -> Unknown)

这个问题可以稍微改善一下

l: Lazy[SomeClass, ...] = Lazy(SomeClass, y=5)
l.to_eager()  # I get (... -> SomeClass)

但是这样做并没有包含参数。

我的问题是 - 在这种情况下,如何在进行变量类型赋值的同时保留参数的类型提示?类型赋值是必要的,比如当我把它和数据类结合使用时。也许 pyright 有什么配置可以避免类型扩展?或者也许 vscode 有什么有用的选项?

我到目前为止尝试过的:

  1. P 作为第二个参数传递给 Lazy[SomeClass, P],但得到了警告,提示 P 在这个上下文中没有意义,而且 VSCode 也没有类型提示。

1 个回答

1

Lazy 单独使用时,相当于 Lazy[Any, Any],这会覆盖 Lazy[SomeClass, int] 推断出的类型。这里的“懒惰”其实是指没有明确指定类型提示,这样编辑器就无法提供参数提示。

... 本身被认为是 types.EllipsisType 的简写。


你希望的是编辑器能够支持某种类型变量绑定的概念,这样你就可以写一个“类型”,它的值会被传递给 Lazy 的实际参数所绑定,类似于

l: Lazy[Cls, T] = Lazy(SomeClass, y=5)

这样 ClsT 就可以(也许仅在这个赋值中)分别绑定到 SomeClassint

撰写回答