Pydantic 和“构造函数”

use*_*918 13 python pydantic fastapi

我是 Pydantic 的新手,并试图了解如何/是否可以创建一个新的类实例。我已阅读 Pydantic 文档,但找不到执行类似操作的示例。

我的 python 代码(在 Pydantic 之前)如下所示:

class Person:
    def __init__(self, id):
        db_result = get_db_content(id)    #lookup id in a database and return a result
        self.name = db_result['name']      
        self.birth_year = db_result['birth_year']

p1 = Person(1234)
print(p1.name)
Run Code Online (Sandbox Code Playgroud)

如果我想根据 id 创建一个 Person 实例,Pydantic 中相应的代码会是什么样子?另外,Pydantic 是否可以为同一个
类提供多个构造函数。例如:

p1 = Person(1234)
p2 = Person("Jane Doe")
Run Code Online (Sandbox Code Playgroud)

Jam*_*s P 15

我不确定这是否是最“迂腐”的做事方式,但解决此问题的一种方法是使用classmethods.

class Person(BaseModel):
    id: int
    name: str
    birth_year: int

    @classmethod
    def from_id(cls, id: int) -> "Person":
        db_result = get_db_content(id)    #lookup id in a database and return a result
        return cls(**db_result)

p1 = Person.from_id(1234)
print(p1.name)
Run Code Online (Sandbox Code Playgroud)


ier*_*dna 10

您可以为此使用标准 __init__ :

from typing import Optional

from pydantic import BaseModel

def get_db_content(id):
    return {
        'name': f'hello {id}',
        'birth_year': 2010,
    }

class Person(BaseModel):
    id: str
    name: Optional[str]
    birth_year: Optional[int]
    def __init__(self, *a, **kw):
        super().__init__(*a, **kw)
        db_result = get_db_content(self.id)
        self.name = db_result['name']      
        self.birth_year = db_result['birth_year']

person = Person(id='15')
print(person.dict())
# {'id': '15', 'name': 'hello 15', 'birth_year': 2010}
Run Code Online (Sandbox Code Playgroud)

不过,就我个人而言,我不会这样做。Pydantic 类旨在用作解析器/验证器,而不是用作功能齐全的对象实体。从这样的类调用数据库方法会将您的类直接耦合到数据库代码,并使测试变得更加困难。

我会这样做:

from pydantic import BaseModel

def get_db_content(id):
    return {
        'name': f'hello {id}',
        'birth_year': 2010,
    }

class Person(BaseModel):
    id: str
    name: str
    birth_year: int

person = Person(id='15', **get_db_content('15'))
print(person.dict())
# {'id': '15', 'name': 'hello 15', 'birth_year': 2010}
Run Code Online (Sandbox Code Playgroud)

注意:代码示例应该是独立的并且按原样工作。

编辑:使用标准 dunder 构造函数而不是 @root_validator


SCo*_*vin 2

目前这还不可能。你必须用类似的东西来创建这个人Person(get_db_content())。

将来您将能够拥有允许这样做的计算字段和上下文。

  • 还没有,我认为可能有一个开放的拉取请求,但我现在没有时间审查它。 (2认同)