python 构造函数参数继承类类型

tez616oj  于 2023-01-08  发布在  Python
关注(0)|答案(1)|浏览(126)

我有一个pydantic类,比如说A类
我想在类上使用root_validator,并希望intelliense帮助我输入类字段
所以我键入values参数"Self"来获取intellisense,但intellisense假设值的字段是点可访问的,所以我将值 Package 在一个"dotdict"类中,允许我以这种方式访问它们
问题是mypy抱怨我的dotdict类在我进行的每次访问上没有属性X
问:如何让dotdict类的示例继承传递给构造函数的参数的类型?

a: Dict[str, Any] = A(foo="bar")
# type(a) -> A
# a.foo -> AttributeError: class A doesn't have an attribute 'foo'
a = dotdict(a)
# a.foo -> "bar"
# type(a) -> dotdict (I want to make it so that a remains of type A after wrapping it with dotdict)
# myclasses.py
from mytools import dotdict
from pydantic import BaseModel, root_validator
from typing_extensions import Self

class A(BaseModel):
  a: int
  b: str

  @root_validator
  def validateA(cls, values: Self): # type: ignore[valid-type]
    """
    Pylance complains about the type for 'values' being unknown
    'values' is a dictionary with the fields of the class, so I type it as Self

    Pylance is satisfied with this and ONLY NOW provides intellisense for 'values'
    (notice my main goal is to get intellisense, but I also prefer the dot notation)
    
    problem is that intellisense recons the fields of the class are dot accessible
    so I wrap 'values' with the 'dotdict' class to make them dot accessible
    THIS causes one big problem:
    mypy complains on every 'values.field' like this: 
    "class 'dotdict' doesn't have an attribute 'field'
    """
    values = dotdict(values) # type: ignore[valid-type]
    assert values.a == int(values.b) , "simple assertion for show purposes"
    return values
# mytools.py
class dotdict(dict): # type: ignore
    """
    a dictionary that supports dot notation and returns 'None' on missing keys
    """
    def __getattr__(self, key: str):
        try:
            v: Optional[Any] = self[key]
            return v
        except KeyError as ke:
            return None

最后要注意的是,mypy抱怨使用'Self'作为类型提示,因此#type:忽略,但我没有找到任何解决方案
谢谢你!

6jjcrrmo

6jjcrrmo1#

正如我在评论中提到的,您无法控制values的类型。它始终是一个字典。但是如果您真的非常需要那些智能感知自动建议,您可以始终创建自己的TypedDict来镜像实际模型,并使用它来注解values

from pydantic import BaseModel, root_validator
from typing import TypedDict

class DictA(TypedDict):
    a: int
    b: str

class A(BaseModel):
    a: int
    b: str

    @root_validator
    def validate_stuff(cls, values: DictA) -> DictA:
        ...
        return values

如果您尝试在方法内部执行类似values["a"].的操作,IDE应该会给予int方法和属性的选择。注意,如果验证器是pre=True,或者您允许任意的额外值,那么该注解仍然是一个谎言,字典可以包含任何内容。
但是,我还是不明白这有什么意义。如果您要对中间变量执行复杂的操作,您可以选择性地将验证器中实际使用的值cast到中间变量中。几乎不需要让IDE知道所有字段的类型。

from pydantic import BaseModel, root_validator
from typing import Any, cast

class A(BaseModel):
    a: int
    b: str

    @root_validator
    def validate_stuff(cls, values: dict[str, Any]) -> dict[str, Any]:
        val_a, val_b = cast(int, values["a"]), cast(str, values["b"])
        ...
        return values

但即使这样看起来也太过了。我无法想象验证器会如此复杂,以至于您真的需要它。

相关问题