将 ParamSec 绑定到方法,但在对象属性内使用函数

问题描述 投票:0回答:1

我想在方法上绑定函数的参数提示,但该函数是我的类属性内部的 BaseModel 子类的构造函数。

这是我的代码:

from pydantic import BaseModel
from typing import TypeVar, Type, Generic

ModelT = TypeVar("ModelT", bound=BaseModel)


class ModelMaker(Generic[ModelT]):

    def __init__(self, model: Type[ModelT]) -> None:
        self.model: Type[ModelT] = model

    def create(self, *args, **kwargs) -> ModelT:
        return self.model(*args, **kwargs)


class MyModel(BaseModel):
    name: str
    age: int


maker = ModelMaker(MyModel)

instance = maker.create() # i would like to get on vscode:
# (method) def create(*, name: str, age: int) -> MyModel
# and not:
# (method) def create(...) -> MyModel

我尝试使用ParamSec,但无法将ParamSec绑定为.model。init

python python-3.x object types type-hinting
1个回答
0
投票

没有经过很好的测试(在我的测试中,

pyright
抱怨它无法解析
pydantic
),但看来你可以用
Type[MyModel]
替换
Callable[P, MyModel]
(并使
MyModel
P
中通用)将
MyModel.__init__
的签名转移到
create

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

P = ParamSpec('P')

ModelT = TypeVar("ModelT", bound=BaseModel)


class ModelMaker(Generic[ModelT, P]):

    def __init__(self, model: Callable[P, ModelT]) -> None:
        self.model: Callable[P, ModelT] = model

    def create(self, *args: P.args, **kwargs: P.kwargs) -> ModelT:
        return self.model(*args, **kwargs)


class MyModel(BaseModel):
    name: str
    age: int

    def __init__(self, n: str, a: int):
        self.n = n
        self.a = a


maker = ModelMaker(MyModel)
reveal_type(maker.create)

我明白了

% py312/bin/pyright tmp.py
/Users/chepner/tmp.py
  /Users/chepner/tmp.py:1:6 - error: Import "pydantic" could not be resolved (reportMissingImports)
  /Users/chepner/tmp.py:28:13 - information: Type of "maker.create" is "(n: str, a: int) -> MyModel"
1 error, 0 warnings, 1 information

当然,这比您的原始代码更通用,因为

model
可以是返回 BaseModel 的任何
可调用函数,而不仅仅是 
BaseModel
 本身的实例。

© www.soinside.com 2019 - 2024. All rights reserved.