【发布时间】:2021-09-27 15:08:27
【问题描述】:
我从 API 收到这样的结构:
from pydantic import BaseModel
class Country(BaseModel):
code: Optional[str] = None
class Address(BaseModel):
street: str
country: Optional[Country] = None
class Person(BaseModel):
firstName: str
lastName: str
address: Optional[Address] = None
如果我想获取国家代码,我需要这样做:
def get_country_code(p: Person):
if p.address and p.adress.country:
return p.address.country.code
return None
如您所见,当我的深度为 3 时,我需要复制 p.address 3 次。在我的实际情况中,数据甚至更加嵌套。
这非常烦人,并且使代码更难阅读。我希望有这样的事情:
def get_country_code(p: Person):
return p.?address.?country.code
属性访问前面的?本质上的意思是“如果后面的属性存在,取它。如果不存在,返回None”
可能的解决方案 #1:转换为 dict
如果是字典,我至少可以这样做:
def get_country_code(p: Person):
return p.get("address", {}).get("country", {}).get("code", None)
因此,我目前正在考虑将其转换回字典...这有点可悲。有没有更好的方法来访问嵌套属性?
可能的解决方案 #2:Dict 默认值 + 修改 BaseModel
我可以将 Optional[Address] 更改为 Union[Address, Dict[str, Any]] 并将默认值设为空字典。但是,Pydantic BaseModel 没有.get(some_str)。因此我需要对其进行修改。
问题
我无法改变数据结构嵌套如此之多或存在许多可为空字段的事实。我只能接受。
有没有办法在不失去编辑器/mypy 支持的情况下拥有.get("attribute", "fallback") 语法?
【问题讨论】:
-
您希望存在的 (
p.?address.?country.code) 确实存在。它叫getattr。 -
@Shinratensei 哦,对了,我完全忘记了这一点????但是,当我使用 getattr 时,我仍然失去了对 mypy / editor 的支持。
-
嗯嗯,你可以随时将
cast()结果发送到Optional[str]