[英]How to not instantiate dataclass members as class variables in Python?
By default, it seems that Python considers the class members as ClassVar.默认情况下,Python 似乎将类成员视为 ClassVar。 Although from the documentation: https://docs.python.org/3/library/dataclasses.html#class-variables
虽然来自文档: https : //docs.python.org/3/library/dataclasses.html#class-variables
One of two places where dataclass() actually inspects the type of a field is to determine if a field is a class variable as defined in PEP 526. It does this by checking if the type of the field is typing.ClassVar.
dataclass() 实际检查字段类型的两个地方之一是确定字段是否是 PEP 526 中定义的类变量。它通过检查字段的类型是否为 Typing.ClassVar 来实现。 If a field is a ClassVar, it is excluded from consideration as a field and is ignored by the dataclass mechanisms.
如果字段是 ClassVar,则将其作为字段排除在外,并被数据类机制忽略。 Such ClassVar pseudo-fields are not returned by the module-level fields() function.
模块级 fields() 函数不会返回此类 ClassVar 伪字段。
A minimal reproduction of the issue:问题的最小再现:
from dataclasses import dataclass
import numpy as np
@dataclass
class Color:
r: int = 0
g: int = 0
b: int = 0
@dataclass
class NumberColor:
color: Color = Color()
number: int = 0
alpha = np.zeros(3)
x = NumberColor()
y = NumberColor()
print("Id of x:", id(x))
print("Id of y:", id(y))
print('-----------')
print("Id of x.color:", id(x.color))
print("Id of y.color:", id(y.color))
print('-----------')
print("Id of x.number:", id(x.number))
print("Id of y.number:", id(y.number))
print('-----------')
print("Id of x.alpha:", id(x.alpha))
print("Id of y.alpha:", id(y.alpha))
print('-----------')
x.color.r = 255
x.number = 10
print(x.__dict__)
print(y.__dict__)
Yields:产量:
Id of x: 140660354709392
Id of y: 140660357249008
-----------
Id of x.color: 140660355994096
Id of y.color: 140660355994096
-----------
Id of x.number: 9788960
Id of y.number: 9788960
-----------
Id of x.alpha: 140660289932624
Id of y.alpha: 140660289932624
-----------
{'color': Color(r=255, g=0, b=0), 'number': 10}
{'color': Color(r=255, g=0, b=0), 'number': 0}
No, the color
attribute of your NumberColor
class isn't being considered a class variable.不,您的
NumberColor
类的color
属性不被视为类变量。 Rather, it's a shared default argument to the __init__
method that's being created for your class by the dataclass
decorator.相反,它是由
dataclass
装饰器为您的类创建的__init__
方法的共享默认参数。
It's not very much different than any other issue with a mutable default argument:它与可变默认参数的任何其他问题没有太大不同:
def foo(c = Color()): # default value is created here
return c
x = foo() # get the default value
print(x.r) # 0, as is expected
x.r = 255
y = foo() # get the default again
print(y.r) # 255, not 0 as you might naively expect
In your code, the equivalent to x
and y
are the x.color
and y.color
attributes.在您的代码中,与
x
和y
等效的是x.color
和y.color
属性。
To avoid this issue, you can assign a dataclasses.field
object to the name in the class body with a default_factory
argument that is the Color
class (you'll also want to do something similar for the numpy array used as the default for alpha
):为避免此问题,您可以使用作为
Color
类的default_factory
参数将dataclasses.field
对象分配给类主体中的名称(您还需要对用作alpha
的默认值的 numpy 数组执行类似操作) :
from dataclasses import dataclass, field
@dataclass
class NumberColor:
color: Color = field(default_factory=Color) # use a field!
number: int = 0
alpha = field(default_factory=lambda: np.zeros(3)) # here too
There's no need to use field
for number
(or for the attributes in Color
) because int
objects are immutable, and you shouldn't care if the same object is being used for any given 0
value.不需要将
field
用于number
(或用于Color
的属性),因为int
对象是不可变的,并且您不应该关心是否将相同的对象用于任何给定的0
值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.