这个似乎就像以前可能被询问过的东西,但是一个小时左右的搜索没有产生任何结果。 Passing default list argument to dataclasses看起来很有前途,但这并不是我想要的。
这是问题所在:当尝试将可变值分配给类属性时,会出现错误:
@dataclass
class Foo:
bar: list = []
# ValueError: mutable default <class 'list'> for field a is not allowed: use default_factory
我从错误消息中收集了应该使用以下内容的信息:
@dataclass
class Foo:
bar: list = field(default_factory=list)
但是为什么不允许可变的默认值?是否要强制避免使用mutable default argument problem?
答案 0 :(得分:2)
我的问题似乎在the docs(如{shmee所述,源自PEP 557)中得到了清楚的回答:
Python将默认成员变量值存储在类属性中。考虑以下示例,不使用数据类:
class C: x = [] def add(self, element): self.x.append(element) o1 = C() o2 = C() o1.add(1) o2.add(2) assert o1.x == [1, 2] assert o1.x is o2.x
请注意,类
C
的两个实例按预期共享相同的类变量x
。使用数据类,如果此代码有效:
@dataclass class D: x: List = [] def add(self, element): self.x += element
它将生成类似于以下内容的代码:
class D: x = [] def __init__(self, x=x): self.x = x def add(self, element): self.x += element
这与使用类
C
的原始示例存在相同的问题。也就是说,在创建类实例时未为D
指定值的类x
的两个实例将共享x
的相同副本。因为数据类仅使用常规的Python类创建,所以它们也共享此行为。数据类没有检测这种情况的通用方法。相反,如果数据类检测到类型为TypeError
,list
或dict
的默认参数,它将引发set
。这是部分解决方案,但可以防止许多常见错误。
答案 1 :(得分:0)
鉴于@dataclass的动机之一是减少样板代码,然后在@dataclass的上下文中
x: list = []
应该等于
x: list = field(default_factory=lambda: [])
仅仅是python像任何东西一样在进行中。
PEP中的示例不合理。应该是:
class D:
def __init__(self, x=[]):
self.x = x
那个
x = None
的作品使整个“工厂”论证更加离奇。为什么无类型有效但列表类型无效?