c1
和c2
的构造函数中的默认值应该为b
和b
生成新的实例变量。相反,它看起来像 c1.a
和 c2.a
引用了同一个变量。 @dataclass
是否正在创建类变量?这似乎与预期的功能不一致,而且我在文档中找不到任何关于类变量的信息。所以,我认为这是一个错误。有人可以向我解释如何解决吗?我应该将其报告为 python 跟踪器上的错误吗?
我知道这个问题一定与 python 通过引用传递对象和通过值传递内置类型的方式有关,因为 b
属性 (它只是一个 float )显示预期/期望的行为,而 a
属性 (这是一个用户定义的对象) 只是一个引用。
谢谢!
代码:
from dataclasses import dataclass
@dataclass
class VS:
v: float # value
s: float # scale factor
def scaled_value(self):
return self.v*self.s
@dataclass
class Container:
a: VS = VS(1, 1)
b: float = 1
c1 = Container()
c2 = Container()
print(c1)
print(c2)
c1.a.v = -999
c1.b = -999
print(c1)
print(c2)
输出:
Container(a=VS(v=1, s=1), b=1)
Container(a=VS(v=1, s=1), b=1)
Container(a=VS(v=-999, s=1), b=-999)
Container(a=VS(v=-999, s=1), b=1)
最佳答案
在 OP 的原始示例中,当定义 Container
类时,将创建单个 VS
对象。然后该对象在 Container
类的所有实例之间共享。这是一个问题,因为用户定义的类(例如 VS
)会导致可变对象。因此,更改任何 Container
对象中的 a
都会更改所有其他 Container
对象中的 a
每次在初始化时实例化 Container
类时,您都希望生成一个新的 VS 对象。为此,使用 field
函数的 default_factory
是一个很好的方法。传递 lambda 函数允许所有这些内联完成。
我将一个 c
成员变量添加到另一个 VS
类的容器中,以说明这样做时成员是独立的。
from dataclasses import dataclass, field
@dataclass
class VS:
v: float # value
s: float # scale factor
def scaled_value(self):
return self.v*self.s
# Use a zero-argument lambda function for default factor function.
@dataclass
class Container:
a: VS = field(default_factory= lambda:VS(1,1) )
b: float = 1
c: VS = field(default_factory= lambda:VS(1,2) )
c1 = Container()
c2 = Container()
print(c1)
print(c2)
c1.a.v = -999
c1.c.s = -999
print(c1)
print(c2)
输出:
Container(a=VS(v=1, s=1), b=1, c=VS(v=1, s=2))
Container(a=VS(v=1, s=1), b=1, c=VS(v=1, s=2))
Container(a=VS(v=-999, s=1), b=1, c=VS(v=1, s=-999))
Container(a=VS(v=1, s=1), b=1, c=VS(v=1, s=2))
关于Python dataclasses.dataclass 引用变量而不是实例变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62852942/