![](/img/trans.png)
[英]What is the purpose of using Field(...) as a default value in pydantic schemas
[英]How to give a Pydantic list field a default value?
我想創建一個 Pydantic model ,其中有一個列表字段,未初始化的默認值為空列表。 有沒有一種慣用的方法來做到這一點?
對於 Python 的內置數據類對象,您可以使用field(default_factory=list)
,但是在我自己的實驗中,這似乎可以防止我的 Pydantic 模型被腌制。 一個天真的實現可能是這樣的:
from pydantic import BaseModel
class Foo(BaseModel):
defaulted_list_field: Sequence[str] = [] # Bad!
但是我們都知道不要使用像空列表文字這樣的可變值作為默認值。
那么給 Pydantic 列表字段一個默認值的正確方法是什么?
對於 pydantic,您可以使用可變默認值,例如:
class Foo(BaseModel):
defaulted_list_field: List[str] = []
f1, f2 = Foo(), Foo()
f1.defaulted_list_field.append("hey!")
print(f1) # defaulted_list_field=['hey!']
print(f2) # defaulted_list_field=[]
它將被正確處理(深度復制),並且每個模型實例都有自己的空列表。
Pydantic 也有default_factory
參數。 在空列表的情況下,結果將是相同的,而是在聲明具有默認值的字段時使用它,您可能希望它是動態的(即每個模型不同) 。
from typing import List
from pydantic import BaseModel, Field
from uuid import UUID, uuid4
class Foo(BaseModel):
defaulted_list_field: List[str] = Field(default_factory=list)
uid: UUID = Field(default_factory=uuid4)
在查看我同事的合並請求時,我看到使用可變 object 作為默認參數並指出了這一點。 令我驚訝的是,它就像對 object 進行了深度復制一樣。 我在項目的自述文件中找到了一個示例,但沒有任何說明。 並且突然意識到開發者一直在忽略這個問題很長一段時間(見底部的鏈接)。
事實上,你可以寫這樣的東西。 並期望正確的行為:
from pydantic import BaseModel
class Foo(BaseModel):
defaulted_list_field: List[str] = []
但是引擎蓋下會發生什么? 我們需要更深入地了解 go...
在快速搜索源代碼后,我發現了這個:
class ModelField(Representation):
...
def get_default(self) -> Any:
return smart_deepcopy(self.default) if self.default_factory is None else self.default_factory()
雖然smart_deepcopy
function 是:
def smart_deepcopy(obj: Obj) -> Obj:
"""
Return type as is for immutable built-in types
Use obj.copy() for built-in empty collections
Use copy.deepcopy() for non-empty collections and unknown objects
"""
obj_type = obj.__class__
if obj_type in IMMUTABLE_NON_COLLECTIONS_TYPES:
return obj # fastest case: obj is immutable and not collection therefore will not be copied anyway
try:
if not obj and obj_type in BUILTIN_COLLECTIONS:
# faster way for empty collections, no need to copy its members
return obj if obj_type is tuple else obj.copy() # type: ignore # tuple doesn't have copy method
except (TypeError, ValueError, RuntimeError):
# do we really dare to catch ALL errors? Seems a bit risky
pass
return deepcopy(obj) # slowest way when we actually might need a deepcopy
此外,如評論中所述,您不能直接在數據庫屬性聲明中使用可變默認值(改用 default_factory)。 所以這個例子是無效的:
from pydantic.dataclasses import dataclass
@dataclass
class Foo:
bar: list = []
並給出:
ValueError: mutable default <class 'list'> for field bar is not allowed: use default_factory
開放討論的鏈接(目前沒有答案):
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.