基于枚举参数的条件返回值键入
我有一些pydantic basemodels,我想用值填充。
from enum import Enum
from typing import Dict, List, Literal, Type, Union, overload
from pydantic import BaseModel
class Document(BaseModel):
name: str
pages: int
class DocumentA(Document):
reviewer: str
class DocumentB(Document):
columns: Dict[str, Dict]
class DocumentC(Document):
reviewer: str
tools: List[str]
示例值:
db = {
"A": {
0: {"name": "Document 1", "pages": 2, "reviewer": "Person A"},
1: {"name": "Document 2", "pages": 3, "reviewer": "Person B"},
},
"B": {
0: {"name": "Document 1", "pages": 1, "columns": {"colA": "A", "colB": "B"}},
1: {"name": "Document 2", "pages": 5, "columns": {"colC": "C", "colD": "D"}},
},
"C": {
0: {"name": "Document 1", "pages": 7, "reviewer": "Person C", "tools": ["hammer"]},
1: {"name": "Document 2", "pages": 2, "reviewer": "Person A", "tools": ["hammer", "chisel"]},
},
}
为了将值加载到正确的基本模型类中,我创建了一个系统类,该类也需要其他地方并且具有更多功能,但是我省略了详细信息以清晰。
class System(Enum):
A = ("A", DocumentA)
B = ("B", DocumentB)
C = ("C", DocumentC)
@property
def key(self)-> str:
return self.value[0]
@property
def Document(self) -> Union[Type[DocumentA], Type[DocumentB], Type[DocumentC]]:
return self.value[1]
然后,通过系统[“ A”]。文档
我可以直接访问documenta
。 要加载值,我使用此函数(暂时忽略处理indexErrors):
def load_document(db: Dict, idx: int, system: System) -> Union[DocumentA, DocumentB, DocumentC]:
data = db[system.key][idx]
return system.Document(**data)
现在,我可能需要处理一些直接加载在处理功能中的B类型数据。
def handle_document_B(db: Dict, idx: int):
doc = load_document(db=db, idx=idx, system=System.B)
# Following line raises mypy errors
# Item "DocumentA" of "Union[DocumentA, DocumentB, DocumentC]" has no attribute "columns"
# Item "DocumentC" of "Union[DocumentA, DocumentB, DocumentC]" has no attribute "columns"
print(doc.columns)
运行mypy会在行上引起错误print(doc.columns)
,因为load> load_document
具有union> Union的键入返回值[docucta,documenta,documenta,documentb,documentb]
,显然documenta
和documentc
无法访问列
属性。但是,这里可以加载的唯一文档类型是documentb
无论如何。
我知道我可以在处理程序功能之外加载文档并改用它,但是我希望将其加载到处理程序中。
我通过将load_document
函数与正确的文档类重载来规避类型问题,但这似乎是一个乏味的解决方案,因为我需要为将来可能会添加的每个系统手动添加一个过载器。
是否可以有条件键入基于枚举输入值的函数返回值?
I have some pydantic BaseModels, that I want to populate with values.
from enum import Enum
from typing import Dict, List, Literal, Type, Union, overload
from pydantic import BaseModel
class Document(BaseModel):
name: str
pages: int
class DocumentA(Document):
reviewer: str
class DocumentB(Document):
columns: Dict[str, Dict]
class DocumentC(Document):
reviewer: str
tools: List[str]
Example Values:
db = {
"A": {
0: {"name": "Document 1", "pages": 2, "reviewer": "Person A"},
1: {"name": "Document 2", "pages": 3, "reviewer": "Person B"},
},
"B": {
0: {"name": "Document 1", "pages": 1, "columns": {"colA": "A", "colB": "B"}},
1: {"name": "Document 2", "pages": 5, "columns": {"colC": "C", "colD": "D"}},
},
"C": {
0: {"name": "Document 1", "pages": 7, "reviewer": "Person C", "tools": ["hammer"]},
1: {"name": "Document 2", "pages": 2, "reviewer": "Person A", "tools": ["hammer", "chisel"]},
},
}
To load the values into the correct BaseModel Class, I have created a System Class, which is also need elsewhere and has more functionality, but I omitted details for clarity.
class System(Enum):
A = ("A", DocumentA)
B = ("B", DocumentB)
C = ("C", DocumentC)
@property
def key(self)-> str:
return self.value[0]
@property
def Document(self) -> Union[Type[DocumentA], Type[DocumentB], Type[DocumentC]]:
return self.value[1]
Then, through System["A"].Document
I can access DocumentA
directly.
To load the values, I use this function (disregard handling IndexErrors for now):
def load_document(db: Dict, idx: int, system: System) -> Union[DocumentA, DocumentB, DocumentC]:
data = db[system.key][idx]
return system.Document(**data)
Now, I might need to handle some of data of type B which I load directly in the handling function.
def handle_document_B(db: Dict, idx: int):
doc = load_document(db=db, idx=idx, system=System.B)
# Following line raises mypy errors
# Item "DocumentA" of "Union[DocumentA, DocumentB, DocumentC]" has no attribute "columns"
# Item "DocumentC" of "Union[DocumentA, DocumentB, DocumentC]" has no attribute "columns"
print(doc.columns)
Running mypy raises errors on the line print(doc.columns)
, since load_document
has a typed return value of Union[DocumentA, DocumentB, DocumentC]
, and obviously DocumentA
and DocumentC
cannot access the columns
attribute. But the only Document type that could be loaded here is DocumentB
anyways.
I know I could load the Document outside of the handler function and pass it instead, but I would prefer to load it in the handler.
I circumvented the type issue by overloading the load_document
function with the correct Document class, but this seems like a tedious solution since I need to manually add an overloader for each System that might be added in the future.
Is it possible to conditionally type hint a functions return value based on an Enum input value?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以根据选定的选项明确注释返回类型:
现在代码的其余代码现在(游乐场)。
You can explicitly annotate return types depending on selected option:
The rest of your code typechecks now (playground).