允许 BaseModel pydantic 的位置参数

问题描述 投票:0回答:4

我有一个包含所有必要参数的类。但是,对于 init 函数,它要求关键字参数,并且不接受位置参数。所以,我的问题是:我可以在 pydantic.BaseModel 的配置中更改一些内容以允许位置参数吗?

这是我的班级的一个例子:

class Foo(BaseModel):
    a: int
    b: Optional[str]
    c: Optional[float]

当我初始化类时,我需要传递关键字参数: Image of a class parameters

所以,我无法像这样初始化类:

Foo(1,2,2.5)
# instead, I should init it like this:
Foo(a=1,b=2,c=2.5)

所以,我需要能够将位置关键字传递给类。可以吗?

python pydantic
4个回答
6
投票

在 pycharm 中使用的带有类型提示的覆盖

__init__
方法示例

class Foo(BaseModel):
    a: int
    b: Optional[str]
    c: Optional[float]
    
    def __init__(self, a: int,
                 b: Optional[str] = None,
                 c: Optional[float] = None,
                 **kwargs) -> None:
        super(Foo, self).__init__(a=a, b=b, c=c, **kwargs)

1
投票

Pydantic 对象不支持位置参数,除非你按照 Arseniy Lebedev 的建议自己实现它。

这是为什么呢? 以下是一些原因

  • 当你有很多字段时 - 很容易将另一个字段添加到模型中,突然所有假设字段具有给定位置的代码都会默默地中断
  • 仅注释字段意味着 pydantic 模型字段的顺序与代码中的顺序不同。
import json
from pydantic import BaseModel
from typing import Optional

class Foo(BaseModel):
    a: int
    b: Optional[str]
    c: Optional[float]

您可以为 Pydantic 提供您想要用来初始化模型的每个密钥(您所做的):

Foo(a=1,b="2",c=2.5)

或者你可以使用 json:

json_raw = '{"a": 1, "b": "2", "c": 3}'
some_dict = json.loads(json_raw)
my_foo = Foo(**some_dict)

或两者的混合:

json_raw = '{"a": 1, "b": "2"}'
some_dict = json.loads(json_raw)
my_foo = Foo(**some_dict, c=3)

1
投票

请勿使用此代码:

def model_from_args(model, args):
    return model(**{field: arg for field, arg in zip(model.model_fields, args)})

更改模型后,破坏代码的可能性非常高。


0
投票

您可以使用创建带有位置参数的对象的类方法来扩展

BaseModel
类。
cls.__annotations__
返回你的 pydantic 字段的字典(按照你声明它们的顺序)。使用
*args
,您可以通过使用可用于实例化对象的位置参数压缩字段来创建字典。

from pydantic import BaseModel

class MasterObj(BaseModel):
    @classmethod
    def create_from_list(cls, *args):
        annotations = cls.__annotations__
        zipped = dict(zip(annotations, args))
        return cls(**zipped)

class Specs(MasterObj):
    spec_type: str 
    hp: int = 0
    attack: int = 0
    spattack: int = 0
    defence: int = 0
    spdefence: int = 0
    speed: int = 0

if __name__ == '__main__':
    s = Specs.create_from_list('main', 100, 100, 100, 100, 100, 100)

您还可以实现一些错误处理来捕获是否提供了过多或过少的位置参数等。

© www.soinside.com 2019 - 2024. All rights reserved.