场景还原
最近开发遇到一个问题是在python3.7
的dataclass
中不能使用可变的默认值,错误如下:
@dataclass
class Foo:
bar: list = []
# ValueError: mutable default <class 'list'> for field a is not allowed: use default_factory
收到这种错误之后,修改为如下即可:
from dataclasses import (
dataclass,
field
)
@dataclass
class Foo:
bar: list = field(default_factory=list)
深层解读
看起来我的问题在文档中得到了很清楚的回答(来自PEP 557,正如shmee所提到的):
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。这是一个部分解决方案,但它可以防止许多常见错误。
网友评论