如何为泛型工厂方法的参数实现静态类型分析?
让Pyright静态检查工厂方法参数合法性的实现方案
我有一个工厂方法,接收类类型及相关参数来创建资源,运行时非法参数会触发Pydantic的ValidationError,但希望Pyright能在编码阶段就静态识别出这些非法参数,比如下面代码中的g=4:
from typing import Type from pydantic import BaseModel class Res(BaseModel): f: int class Config: extra = "forbid" def factory[T](resource_type: Type[T], **kwargs) -> T: return resource_type(**kwargs) factory(Res, f=3) # 运行正常 factory(Res, f=3, g=4) # 运行时触发ValidationError,但Pyright无静态提示
我尝试用ParamSpec实现但报错:
def factory[T, **P](resource_type: Type[T], *args: P.args, **kwargs: P.kwargs) -> T: return resource_type(**kwargs) factory(Res, f=3) # Pyright提示:Param spec "P@factory" has no bound value
解决方案
要实现静态参数检查,需要将工厂函数的参数与目标类的构造函数参数绑定,以下是两种可行方式:
方式一:直接绑定构造函数的参数签名
利用ParamSpec和Callable,直接让工厂函数接收类的构造函数(类本身就是可调用对象),这样Pyright会自动关联构造函数的参数要求:
from typing import Callable, ParamSpec, TypeVar from pydantic import BaseModel P = ParamSpec("P") T = TypeVar("T") class Res(BaseModel): f: int class Config: extra = "forbid" def factory(resource_type: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: return resource_type(*args, **kwargs) factory(Res, f=3) # 无提示,正常 factory(Res, f=3, g=4) # Pyright静态提示:Unexpected keyword argument "g" for "Res"
方式二:通过Protocol定义可构造的类类型
如果需要明确接收Type[T]类型的参数,可以用Protocol定义一个具有特定构造签名的类协议,让工厂函数接收符合该协议的类:
from typing import Type, Protocol, ParamSpec, TypeVar P = ParamSpec("P") T = TypeVar("T") class Constructable(Protocol[P, T]): def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: ... class Res(BaseModel): f: int class Config: extra = "forbid" def factory(resource_type: Constructable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: return resource_type(*args, **kwargs) factory(Res, f=3) # 无提示,正常 factory(Res, f=3, g=4) # Pyright静态提示非法参数
两种方式都能让Pyright在编码阶段就识别出不符合目标类构造要求的参数,提前发现问题。
内容的提问来源于stack exchange,提问作者Guillaume
相关产品推荐
相关产品推荐

