[Chore/Refactor] unify use Field for dict field #16221

Closed
opened 2026-02-21 19:25:09 -05:00 by yindo · 1 comment
Owner

Originally created by @asukaminato0721 on GitHub (Aug 17, 2025).

Originally assigned to: @hyongtao-code on GitHub.

Self Checks

  • I have read the Contributing Guide and Language Policy.
  • This is only for refactoring, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report, otherwise it will be closed.
  • 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
  • Please do not modify this template :) and fill in all the required fields.

Description

class Data(BaseModel):
    ...
    extras: dict = {}

should use Field(default_factory=dict)

Motivation

dict is mutable

Additional Context

No response

Originally created by @asukaminato0721 on GitHub (Aug 17, 2025). Originally assigned to: @hyongtao-code on GitHub. ### Self Checks - [x] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542). - [x] This is only for refactoring, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general). - [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [x] I confirm that I am using English to submit this report, otherwise it will be closed. - [x] 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :) - [x] Please do not modify this template :) and fill in all the required fields. ### Description ```py class Data(BaseModel): ... extras: dict = {} ``` should use `Field(default_factory=dict)` ### Motivation dict is mutable ### Additional Context _No response_
yindo added the good first issue label 2026-02-21 19:25:09 -05:00
yindo closed this issue 2026-02-21 19:25:09 -05:00
Author
Owner

@hyongtao-code commented on GitHub (Aug 18, 2025):

@asukaminato0721 Thanks! I’ve learned a lot of Pythonic tips and best practices from many of your issues and PRs.

I came across a very relevant reference: Stackoverflow and I also did some experiments locally (Python 3.12).

(1) example with dataclasses

from dataclasses import dataclass, field

@dataclass
class BadDataclass:
    data: dict = {}  # ⚠️ multiple instances will share the same dict

d1 = BadDataclass()

This immediately raises an error:

ValueError: mutable default <class 'dict'> for field data is not allowed: use default_factory

(2) example with pydantic.BaseModel

from pydantic import BaseModel

class BadButSafeModel(BaseModel):
    data: dict = {}  # Pydantic will deepcopy the default value

m1 = BadButSafeModel()
m2 = BadButSafeModel()

m1.data["x"] = 1
print("m1.data:", m1.data)  # {'x': 1}
print("m2.data:", m2.data)  # {}    ← not polluted

Output:

m1.data: {'x': 1}
m2.data: {}

This works safely in Pydantic because it internally uses _utils.smart_deepcopy(). So unlike dataclass, Pydantic ensures that each instance gets its own copy.

Summary

  • Dataclasses: explicitly forbid data: dict = {} and require default_factory.

  • Pydantic: allows data: dict = {} safely because of deep copy, but still recommends using Field(default_factory=dict) for clarity and better extensibility.

👉 In short: Dataclasses enforce safety by disallowing mutable defaults, while Pydantic makes it safe internally, but the explicit default_factory style is still preferred.

Of course, I’d be happy to take this on. Could you please assign this issue to me? @crazywoola

@hyongtao-code commented on GitHub (Aug 18, 2025): @asukaminato0721 Thanks! I’ve learned a lot of Pythonic tips and best practices from many of your issues and PRs. I came across a very relevant reference: [Stackoverflow](https://stackoverflow.com/questions/63793662/how-to-give-a-pydantic-list-field-a-default-value) and I also did some experiments locally (Python 3.12). ### (1) example with dataclasses ``` python from dataclasses import dataclass, field @dataclass class BadDataclass: data: dict = {} # ⚠️ multiple instances will share the same dict d1 = BadDataclass() ``` This immediately raises an error: ``` bash ValueError: mutable default <class 'dict'> for field data is not allowed: use default_factory ``` ### (2) example with pydantic.BaseModel ```python from pydantic import BaseModel class BadButSafeModel(BaseModel): data: dict = {} # Pydantic will deepcopy the default value m1 = BadButSafeModel() m2 = BadButSafeModel() m1.data["x"] = 1 print("m1.data:", m1.data) # {'x': 1} print("m2.data:", m2.data) # {} ← not polluted ``` Output: ``` bash m1.data: {'x': 1} m2.data: {} ``` This works safely in `Pydantic` because it internally uses `_utils.smart_deepcopy()`. So unlike `dataclass`, `Pydantic` ensures that each instance gets its own copy. ## Summary - Dataclasses: explicitly forbid data: dict = {} and require default_factory. - Pydantic: allows data: dict = {} safely because of deep copy, but still recommends using Field(default_factory=dict) for clarity and better extensibility. 👉 In short: Dataclasses enforce safety by disallowing mutable defaults, while Pydantic makes it safe internally, but the explicit default_factory style is still preferred. Of course, I’d be happy to take this on. Could you please assign this issue to me? @crazywoola
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#16221