You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用别名时Pydantic抛出额外属性错误,原因是什么?

问题:Pydantic使用别名时,原字段名被判定为额外参数?

代码示例

from typing import Literal
from pydantic import BaseModel, Field, ConfigDict


class Base(BaseModel):
    # 让继承类可以像字典一样通过下标访问属性,比如 value = class['key']
    def __getitem__(self, item):
        return getattr(self, item)

    model_config = ConfigDict(extra='forbid')

class Foo(Base):
    bar: Literal['bar1', 'bar2'] = Field(default=None, frozen=True, alias="bar_path")

a = {'bar': 'bar1'}
b = Foo(**a)

触发的异常

Traceback (most recent call last):
  File "/home/hawk/applications/pydantic_example.py", line 16, in <module>
    b = Foo(**a)
        ^^^^^^^^
  File "/home/hawk/miniconda3/envs/bird/lib/python3.11/site-packages/pydantic/main.py", line 164, in __init__
    __pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)
pydantic_core._pydantic_core.ValidationError: 1 validation error for Foo
bar
  Extra inputs are not permitted [type=extra_forbidden, input_value='bar1', input_type=str]
    For further information visit https://errors.pydantic.dev/2.5/v/extra_forbidden

移除别名后代码可正常运行;若保留别名并传入{'bar_path': 'bar1'}也可正常运行。请问为何别名会导致原字段被视为额外参数?


原因分析

这是Pydantic 2.x的默认行为:当你给字段指定alias后,默认只会把别名作为合法的输入键,原字段名不会被自动识别为该字段的输入。而你设置了extra='forbid',禁止额外字段,所以传入原字段名bar时,Pydantic会把它当成未定义的额外字段,触发验证错误。

解决方案

如果需要同时支持原字段名和别名作为输入,只需在model_config中添加populate_by_name=True配置:

class Base(BaseModel):
    def __getitem__(self, item):
        return getattr(self, item)

    # 添加populate_by_name=True,让Pydantic同时识别字段原名和别名
    model_config = ConfigDict(extra='forbid', populate_by_name=True)

class Foo(Base):
    bar: Literal['bar1', 'bar2'] = Field(default=None, frozen=True, alias="bar_path")

a = {'bar': 'bar1'}
b = Foo(**a)  # 现在可以正常实例化

这个配置会告诉Pydantic在解析输入数据时,同时匹配字段的原名和别名,这样两种键名都会被正确识别。


内容的提问来源于stack exchange,提问作者alexv9

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 21:12:49