Pydantic 和 Dataclass 都可以根据属性及其类型来提示对象创建,如以下示例所示:
from pydantic import BaseModel, PrivateAttr, Field
from dataclasses import dataclass
# Pydantic way
class Person(BaseModel):
name : str
address : str
_valid : bool = PrivateAttr(default=False)
#dataclass way
@dataclass
class PersonDataclass():
name : str
address : str
_valid : bool = False
bob = Person(name="Bob", address="New York")
bobDataclass = PersonDataclass("Bob", "New York")
使用此代码,我可以获得有关对象创建的类型提示(请参见下面的屏幕截图):
不仅如此,对象的属性也被记录下来。
我研究了pydantic的代码,试图达到同样的结果,但我做不到。我尝试的代码是这样的:
class MyBaseModelMeta(type):
def __new__(cls, name, bases, dct):
def new_init(self : cls, /, name : str, address : str):
self.name = name
self.address = address
self._valid = False
dct["__init__"] = new_init
dct["__annotations__"] = {"__init__": {"name": str, "address": str, "_valid": bool}}
return super().__new__(cls, name, bases, dct)
class MyBaseModel(metaclass=MyBaseModelMeta):
def __repr__(self) -> str:
return f"MyBaseModel: {self.__dict__}"
class MyPerson(MyBaseModel):
pass
myBob = MyPerson("Bob", "New York")
我的类有效(动态 init 插入有效),但类和对象没有得到类型提示。
我做错了什么?我怎样才能实现类型提示?
@chepner 是对的。
静态类型检查器不会执行您的代码,它们只是读取它。
回答你的问题 Pydantic 和
dataclasses
是如何做到的 - 他们作弊:
特殊插件允许
mypy
推断实际上仅在运行时创建的签名。 (当然,我只是开玩笑说“作弊”,但你明白我的意思。)
如果您希望静态类型检查器考虑您自己的动态注释,您将 have 为它们编写自己的插件。
@Daniil Fajnberg 大部分是正确的,
dataclass_transform
(Python 3.11)
__dataclass_transform__
早期采用者计划装饰器。
Pylance 和 Pyright(通常在 VS-Code 中使用)至少可以使用这些。
尽管如此,您只能模仿数据类的行为,但我认为您无法定义您的元类添加额外的字段。 :/
编辑: 至少 pydantic 将这个装饰器用于他们的 BaseModel:https://pydantic-docs.helpmanual.io/visual_studio_code/#technical-details
如果你仔细研究 pydantic 的代码,你会发现他们的 ModelMetaclass 是用
__dataclass_transform__
装饰的