Python dataclasses.dataclass 引用变量而不是实例变量

标签 python instance-variables class-variables

c1c2 的构造函数中的默认值应该为bb 生成新的实例变量。相反,它看起来像 c1.ac2.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/

相关文章:

python - 如何检查我的角色正在与哪个物体发生碰撞?

ruby - 局部变量、实例变量和类变量有什么区别?

python - 更改静态类变量

python - 有没有办法让 tkinter 中的网格居中?

python - 在另一个列表中编码列表元素存在的最有效方法

python - 登录认证系统

java - 局部引用变量也称为组合吗?

python - 有没有办法在引用原始列表的同时将列表元素转换为自变量?

python 3 : Can we avoid repeating an instance name when calling several of its methods?

c++ - 继承的构造函数和附加变量的解决方法