簡體   English   中英

如何給 Pydantic 列表字段一個默認值?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM