我想以某种方式绑定(bind)我的 TypedDict (我用于数据库结果类型提示)和我的 Dataclass。
我并不是说它可能很难实现,并且 TypedDict 只是运行时的字典,但无论如何。
从逻辑上讲,从设计和架构的角度来看,它听起来更合理、更一致、更整洁。
嗯,实现不应该影响设计。
from typing import TypedDict
from dataclasses import dataclass
class UserDB(TypedDict):
id: int
# Causing error ValueError: no signature found for builtin type <class 'dict'>
@dataclass
class UserDC(UserDB):
# "id: int" should be inherited from `TypedDict`
name: str
# Or at least I want:
@dataclass
class AnotherUserDC:
db_data: UserDB
预期:
领域UserDC.id
(至少类型提示)应该继承自 TypedDict
实际:
ValueError: no signature found for builtin type <class 'dict'>
最佳答案
typing.TypedDict
与数据类有本质上的不同 - 首先,在运行时,它绝对不执行任何操作,并且行为就像一个普通字典(但提供用于创建它的元信息) .
它将接受未知字段和无效类型,它仅适用于获取 [ ]
语法的项目,不适用于点属性语法等...
因此,更容易做的事情是在运行数据类装饰器之前将类型字典的元信息注入(inject)数据类元信息。
如果您不需要继承关系 - 即您的代码在任何时候都不会询问 UserDC 对象是否是 UserDB 的实例,那么就可以了。
为了做到这一点,一个简短的中间装饰器将完成这项工作:
def inject_fields(parent):
def doit(cls):
cls.__annotations__ = parent.__annotations__ | cls.__annotations__
return cls
return doit
# and then:
class UserDB(TypedDict):
id: int
@dataclass
@injectfields(UserDB)
class UserDC:
# "id: int" is injected from `TypedDict`
name: str
现在,如果您需要 OOP 继承关系 - 即 isinstance(UserDC(...), UserDB)
预计返回 True
,我首先请求您回顾一下你的建模:它几乎没有任何意义,正如我在答案开头所说的那样:在Python中,一个字典是一个东西,一个数据类是另一个东西。
如果您正在处理除 TypedDict 之外的任何其他类型,并且仍然遇到这一点,由于您的特定设置中的任何原因(例如,UserDB 来自另一个团队创建的项目),Python 将提供“虚拟子类化”解决方法:当类可以回答其他类的子类而无需任何“物理”继承关系时。 但是,typing.TypedDict 特别不遗余力地确保这种方式被阻止。它实际上只是静态类型检查的东西,而不是在运行时仅用作普通字典。
检查输入模块源代码typing.py
中的相关片段:
def __subclasscheck__(cls, other):
# Typed dicts are only for static structural subtyping.
raise TypeError('TypedDict does not support instance and class checks')
关于Python绑定(bind)Dataclass和TypedDict(从TypedDict继承Dataclass),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74507348/