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

c1和c2的构造函数中的默认值应为b和b产生新的实例变量。相反,看起来c1.a和c2.a引用了相同的变量。 @dataclass是否正在创建类变量?这似乎与预期的功能不一致,并且我在文档中找不到有关类变量的任何信息。因此,我认为这是一个错误。有人可以向我解释如何解决吗?我应该将其报告为python跟踪器上的错误吗?

我知道这个问题与python通过引用传递对象和通过值传递内置类型的方式有关,因为b属性(只是一个浮点数)显示了预期/期望的行为,而a属性(这是一个a用户定义的对象)只是一个参考。

谢谢!

从数据类导入数据类

“”“输入”“”

@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,b=1)
Container(a=VS(v=-999,b=-999)
Container(a=VS(v=-999,b=1)
iCMS 回答:Python dataclasses.dataclass引用变量而不是实例变量

在OP的原始示例中,定义了VS类时,将创建一个Container对象。然后,该对象将在Container类的所有实例之间共享。这是一个问题,因为诸如VS之类的用户定义类会导致可变对象。因此,在任何a对象中更改Container将在所有其他a对象中更改Container

您希望每次在初始化时实例化Container类时都生成一个新的VS对象。为此,使用default_factory函数的field是解决问题的好方法。传递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=2))
Container(a=VS(v=-999,s=-999))
Container(a=VS(v=1,s=2))
,

感谢Eric S提供的解释:

“”“ c1和c2共享a的相同实例。这是可变的默认参数问题:https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments

使用default_factory为每个容器创建一个新的VS。 “”“

default_factory不允许我为多个属性使用唯一的一组默认VS值,因为需要在VS数据类中定义VS默认值。例如,如果我希望a默认为VS(1,1),但我希望b默认为VS(1,2),则default_factory对我没有帮助。因此,我发现了一种解决方法,即创建关键字条目的字典并将深拷贝传递到我的Container()构造函数中(请注意,如果我不传递深拷贝,则会遇到与上述相同的问题)。这是我的最终代码段和输出:

“”“代码”“”

@dataclass
class VS:
    v: float = 1 # value
    s: float = 1 # scale factor
    
    def scaled_value(self):
        return self.v*self.s

@dataclass
class Container:
    a: VS = field(default_factory=VS)
    b: float = 1

ip = {'a':VS(2,1),'b':1}
c1 = Container(**deepcopy(ip))
c2 = Container(**deepcopy(ip))

print(c1)
print(c2)

c1.a.v = 0
c1.b = 0

print(c1)
print(c2)

“”“”输出“”“

容器(a = VS(v = 2,s = 1),b = 1)

容器(a = VS(v = 2,s = 1),b = 1)

容器(a = VS(v = 0,s = 1),b = 0)

容器(a = VS(v = 2,s = 1),b = 1)

本文链接:https://www.f2er.com/1954610.html

大家都在问