gpt4 book ai didi

python - 为什么 pydantic 数据类将列表转换为字典?如何防止这种行为?

转载 作者:行者123 更新时间:2023-12-05 03:17:45 38 4
gpt4 key购买 nike

我对 pydantic 数据类的行为有点困惑。为什么 dict 类型接受 dictlist 作为有效的 dict 以及为什么将其转换为键的 dict?难道我做错了什么?这是某种有意为之的行为吗?如果是,是否有办法阻止这种行为?

代码示例:

from pydantic.dataclasses import dataclass

@dataclass
class X:
y: dict
print(X([{'a':'b', 'c':'d'}]))

输出:

X(y={'a': 'c'})

最佳答案

哈,这其实有点有趣。忍受我...


Why does the dict type accept a list of a dict as valid dict and why is it converted it to a dict of the keys?

这可以在我们仔细查看默认值 dict_validator 时得到解释。由 Pydantic 模型使用。它所做的第一件事(对任何非 dict)是尝试将值强制转换为 dict

用你的具体例子试试这个:

y = [{'a': 'b', 'c': 'd'}]
assert dict(y) == {'a': 'c'}

这是为什么?

嗯,初始化一个dict ,您可以传递不同类型的参数。一种选择是传递一些 Iterable

Each item in the iterable must itself be an iterable with exactly two objects. The first object of each item becomes a key in the new dictionary, and the second object the corresponding value.

在您的示例中,您恰好有一个可迭代对象(特别是 list),并且该可迭代对象中唯一的项目本身就是一个可迭代对象(特别是 dict) .字典是如何默认迭代的?通过他们的 key !由于该字典 {'a': 'b', 'c': 'd'} 恰好有两个键值对,这意味着当迭代它时会产生这两个键,即 “a”“c”:

d = {'a': 'b', 'c': 'd'}
assert tuple(iter(d)) == ('a', 'c')

正是这种机制允许从 2 元组的列表中构造一个 dict,例如:

data = [('a', 1), ('b', 2)]
assert dict(data) == {'a': 1, 'b': 2}

的情况下,这会导致您显示的结果,乍一看似乎很奇怪和出乎意料,但当您考虑字典初始化的逻辑时,实际上是有道理的。

有趣的是,当 list 中的 dict 具有恰好 两个键时,这有效-值对!多一点或少一点都会导致错误。 (自己尝试一下。)

简而言之:这种行为既不是 Pydantic 也不是数据类的特殊行为,而是常规 dict 初始化的结果。


Am i doing something wrong?

我会说,是的。您尝试分配给 X.y 的值是一个 list,但您声明它是一个 dict。所以这显然是错误的。我知道有时数据来自外部来源,所以这可能不取决于您。


Is this some kind of intended behavior [...]?

从某种意义上说,这是一个很好的问题,我很想知道 Pydantic 团队是否知道这种边缘情况及其导致的奇怪结果。我想说,字典验证器的实现方式至少是可以理解的。


is there a way to prevent that behavior?

是的。除了不在那里传递列表的明显解决方案之外。

您可以添加自己的自定义验证器,使用 pre=True 对其进行配置,并使其成为例如 允许实际直接的 dict 实例以进行进一步验证。然后你可以立即捕获这个错误。


希望这对您有所帮助。

感谢您对此有所启发,因为一开始这也会让我失望。我想我会开始深入研究 Pydantic 问题跟踪器和 PR,看看是否可以/应该/将以某种方式解决这个问题。

附言

这是前面提到的“严格”验证器的非常简单的实现,它可以防止 dict 强制转换,而是立即为非 dict 引发错误:

from typing import Any

from pydantic.class_validators import validator
from pydantic.dataclasses import dataclass
from pydantic.fields import ModelField, SHAPE_DICT, SHAPE_SINGLETON


@dataclass
class X:
y: dict

@validator("*", pre=True)
def strict_dict(cls, v: Any, field: ModelField) -> Any:
declared_dict_type = (
field.type_ is dict and field.shape is SHAPE_SINGLETON
or field.shape is SHAPE_DICT
)
if declared_dict_type and not isinstance(v, dict):
raise TypeError(f"value must be a `dict`, got {type(v)}")
return v


if __name__ == '__main__':
print(X([{'a': 'b', 'c': 'd'}]))

输出:

Traceback (most recent call last):
File "....py", line 24, in <module>
print(X([{'a': 'b', 'c': 'd'}]))
File "pydantic/dataclasses.py", line 313, in pydantic.dataclasses._add_pydantic_validation_attributes.new_init

File "pydantic/dataclasses.py", line 416, in pydantic.dataclasses._dataclass_validate_values
# worries about external callers.
pydantic.error_wrappers.ValidationError: 1 validation error for X
y
value must be a `dict`, got <class 'list'> (type=type_error)

关于python - 为什么 pydantic 数据类将列表转换为字典?如何防止这种行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73948788/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com