高级泛型类型批注

Advanced generic type annotations

提问人:Jiří Kubica 提问时间:10/11/2023 最后编辑:arun n aJiří Kubica 更新时间:10/12/2023 访问量:57

问:

我有一个 Wrapper 类(<<T.init>>是我正在努力解决的部分):

T = TypeVar('T')

class Wrapper(Generic[T]):
    def __init__(**kwargs: <<T.__init__>>):
        self.kwargs = kwargs
        ...

    def __call__() -> T:
        return self.__orig_class__.__args__[-1](**self.kwargs)

我是这样使用它的:

wrapped_class = Wrapper[SomeClass](**SomeClass_arguments)

SomeClass_arguments 是 SomeClass 对其 init 方法的参数

我想让静态类型检查和提示对SomeClass_arguments有用。 我能够使用 inspect 模块动态检查它们。但我宁愿选择静态解决方案。我并不总是控制 SomeClass,因为它可以是我的类,也可以是一些第三方类。

我无法讨论这种设计的真正意图。但是我需要包装(添加一些级别的功能)一个对象,同时将对象定义和初始化wrapped_class()分开。wrapped_class = Wrapper[SomeClass](**SomeClass_arguments)

Python 泛型 注解包装 类型变量

评论


答:

0赞 David 10/11/2023 #1

你可以试试这个:

from typing import Callable, Generic, ParamSpec, TypeVar

T = TypeVar('T')
P = ParamSpec('P')

class Wrapper(Generic[T]):
    def __init__(self, cls: Callable[P, T], *args: P.args, **kwargs: P.kwargs):
        self._cls = cls
        self.args = args
        self.kwargs = kwargs

    def __call__(self) -> T:
        return self._cls(*self.args, **self.kwargs)

wrap = Wrapper(int, '123')  # OK
wrap = Wrapper(int, [])  # gives error: list not compatible with arguments of int

它使用 其中 P 是 a 来指定类型。从第一个参数和传递的参数推断出来。Callable[P, T]ParamSpecP

评论

0赞 Jiří Kubica 10/12/2023
谢谢你的好解决方案。不过,这有一个缺陷。当调用 wrap 实例时,它不知道它会产生 int。我必须像这样定义它(Wrapper[int](int, 1)),它重复了类的名称。但这是进步,也是一个有趣的功能。谢谢
0赞 David 10/12/2023
不,你不需要重复.传入的参数足以让静态检查器知道返回类型为 。由类型检查器推断。[int]intint[int]
0赞 Jiří Kubica 10/12/2023
您使用的是哪个版本的 python 和 IDE?我的 pycharm 不会向我显示我尝试使用的任何类的任何提示。
0赞 Jiří Kubica 10/12/2023
另外,如果我能让它像这样工作 def __class_getitem__(cls, params: Callable[P, T]): return super().__class_getitem__(params) 这将允许我保留我的旧语法,但遗憾的是我无法使它正常工作
0赞 David 10/12/2023
我将 Visual Studio Code 与 Python 3.11.4 一起使用。上面的代码运行良好,类型检查器在最后一行显示错误。