我想实现一个自定义列表。基本上,它应该像普通列表一样运行,除非使用
__contains__
函数。如果列表为空,我们认为它包含所有内容。
然后我想在继承自 BaseModel 的 pydantic 模型中使用这个自定义列表。
该类的实现如下:
class ListAllIfEmpty(list):
"""
Normal list. If the list is empty we will consider it contains
everything
"""
def __contains__(self, item):
if not self:
return True
else:
return super().__contains__(item)
当我尝试将其用作 BaseModel 中的属性并为其指定默认值时,我收到有关为
ListAllIfEmpty
生成架构的错误。我收到将 arbitrary_types_allowed
设置为 true 的建议。如果我这样做,pydantic 将停止对对象进行验证。尽管如此,我还是希望 Pydantic 使用普通的 python 内置列表来完成所有检查。具有 ListAllIfEmpty
类型属性的类如下所示:
class A(BaseModel):
value1: str
value2: ListAllIfEmpty[int] = Field(default_factory=lambda: [])
错误信息如下:
E pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for [...].ListAllIfEmpty[typing.Annotated[datetime.date, BeforeValidator(func=<function validate_date at 0x000001EB701040E0>), PlainSerializer(func=<function format_date at 0x000001EB701053A0>, return_type=PydanticUndefined, when_used='unless-none')]]. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it.
E
E If you got this error by calling handler(<some type>) within `__get_pydantic_core_schema__` then you likely need to call `handler.generate_schema(<some type>)` since we do not call `__get_pydantic_core_schema__` on `<some type>` otherwise to avoid infinite recursion.
我发现使用 RootModel 可能会有所帮助。尽管如此,我还没有从文档中完全理解它是如何工作的。我也看到一些人提到“Annotated”,但我只看到人们用它来添加验证信息。我还想保持“ListAllIfEmpty”的行为与普通列表相同,也就是说,能够像
a = [1,2,3]
那样实例化它。
您应该使
ListAllIfEmpty
继承 RootModel
,并将 root
设置为您想要的任何类型。__contains__
或其他 root
方法。
class ListAllIfEmpty(RootModel):
"""
Normal list. If the list is empty we will consider it contains everything
"""
root: list[int] = Field(default_factory=list)
def __contains__(self, item):
if not self.root:
return True
else:
return item in self.root
def __getitem__(self, item):
return self.root[item]
def __iter__(self):
return iter(self.root)
class A(BaseModel):
value1: str
value2: ListAllIfEmpty = Field(default_factory=ListAllIfEmpty)
我在这些操作上测试了一下,这是你想要的吗?
a = A(value1="test", value2=ListAllIfEmpty())
print(1 in a.value2) # True
b = A(value1="test", value2=list())
print(1 in b.value2) # True
c = A(value1="test", value2=[1, 2, 3])
print(1 in c.value2) # True
print(4 in c.value2) # False
d = A(value1="test")
print(1 in d.value2) # True
A(value1="test", value2=[1,"2",3]) # Pass
A(value1="test", value2=[1,"bad",3]) # Fail