![](/img/trans.png)
[英]How to not instantiate dataclass members as class variables in Python?
[英]Python dataclass inheritence with class variables
考虑以下示例代码
from dataclasses import dataclass, field
from typing import ClassVar
@dataclass
class Base:
x: str = field(default='x', init=False)
@dataclass
class A(Base):
name: str
@dataclass
class B(Base):
name: str
a = A('test_a')
b = B('test_b')
a.x = 'y'
a.x # prints 'y'
b.x # prints 'x'
它按预期打印“y”和“x”。
现在我想让x
成为dict
类型的 ClassVar :
from dataclasses import dataclass, field
from typing import ClassVar, Dict
@dataclass
class Base:
x: ClassVar[Dict[str, str]] = field(default={'x': 'x'}, init=False)
@dataclass
class A(Base):
name: str
@dataclass
class B(Base):
name: str
a = A('test_a')
b = B('test_b')
a.x['y'] = 'y'
a.x
b.x
但是,现在 output 是
a.x => {'x': 'x', 'y': 'y'}
b.x => {'x': 'x', 'y': 'y'}
我希望只有ax
被修改并且bx
保持在默认的初始值 `{'x': 'x'}。
如果该字段不是ClassVar
,那么我可以使用default_factory=dict
但这不能与ClassVar
结合使用,因为它会返回错误
Field cannot have a default factory
也许使用__post_init__
你可以解决这个问题
@dataclass
class Base:
# x: ClassVar[Dict[str, str]] = field(default=dict(val), init=False)
def __post_init__(self) :
self.x = {'x':'x'}
Class 变量在父类和所有子类之间共享,因此您似乎想要的(在父类中声明的 class 变量,但子类获得自己可以操作的副本)在概念上是不可能的。
如果要正确执行此操作,则必须在每个子项中重新声明 class 变量:
from dataclasses import dataclass
from typing import ClassVar, Dict
@dataclass
class Base:
x: ClassVar[Dict[str, str]] = {'x': 'x'}
@dataclass
class A(Base):
x: ClassVar[Dict[str, str]] = {'x': 'x'}
name: str
@dataclass
class B(Base):
x: ClassVar[Dict[str, str]] = {'x': 'x'}
name: str
a = A('test_a')
b = B('test_b')
a.x['y'] = 'y'
a.x
b.x
现在给
a.x => {'x': 'x', 'y': 'y'}
b.x => {'x': 'x'}
但如果这太麻烦或不切实际,我有这把漂亮的脚枪给你。 它不是使用ClassVar
s,而是将您的需求明确地编程到基础 class 作为 function,并使其看起来像带有@property
装饰器的属性:
from dataclasses import dataclass
from typing import Dict
@dataclass
class Base:
@property
def x(self) -> Dict[str, str]:
cls = type(self)
# first call per child class instance will initialize a proxy
if not hasattr(cls, "_x"):
setattr(cls, "_x", {"x": "x"}) # store the actual state of "x" in "_x"
return getattr(cls, "_x")
@dataclass
class A(Base):
name: str
@dataclass
class B(Base):
name: str
a_1 = A('test_a_1')
a_2 = A('test_a_2')
b = B('test_b')
a_1.x['y'] = 'y'
a_1.x
a_2.x
b.x
这也仅在子类实例之间正确共享x
,但您不需要在每个新子实例中编写额外的行:
a.x => {'x': 'x', 'y': 'y'}
a_1.x => {'x': 'x', 'y': 'y'}
b.x => {'x': 'x'}
一个警告是,与ClassVar
不同,您不能在没有实例的情况下调用 class 上的属性,例如Ax
将不起作用。 但似乎你并没有试图这样做。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.