提问人:Jiří Kubica 提问时间:10/11/2023 最后编辑:arun n aJiří Kubica 更新时间:10/12/2023 访问量:57
高级泛型类型批注
Advanced generic type annotations
问:
我有一个 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)
答:
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]
ParamSpec
P
评论
0赞
Jiří Kubica
10/12/2023
谢谢你的好解决方案。不过,这有一个缺陷。当调用 wrap 实例时,它不知道它会产生 int。我必须像这样定义它(Wrapper[int](int, 1)),它重复了类的名称。但这是进步,也是一个有趣的功能。谢谢
0赞
David
10/12/2023
不,你不需要重复.传入的参数足以让静态检查器知道返回类型为 。由类型检查器推断。[int]
int
int
[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 一起使用。上面的代码运行良好,类型检查器在最后一行显示错误。
评论