Skip to main content

Python dataclass inheritenceinheritance with class variables

added 71 characters in body
Source Link
wasp256
  • 6.4k
  • 14
  • 78
  • 137

Consider the following example code

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'

which prints 'y' and 'x' as expected.

Now I'd like to make x a ClassVar of type dict:

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

However, now the output is

a.x => {'x': 'x', 'y': 'y'}
b.x => {'x': 'x', 'y': 'y'}

I'd expect that only a.x gets modified and b.x stays at the default init value `{'x': 'x'}.

If the field would not be a ClassVar then I could use the default_factory=dict but that doesn't work in combination with ClassVar. since it returns the error

 Field cannot have a default factory

Consider the following example code

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'

which prints 'y' and 'x' as expected.

Now I'd like to make x a ClassVar of type dict:

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

However, now the output is

a.x => {'x': 'x', 'y': 'y'}
b.x => {'x': 'x', 'y': 'y'}

I'd expect that only a.x gets modified and b.x stays at the default init value `{'x': 'x'}.

If the field would not be a ClassVar then I could use the default_factory=dict but that doesn't work in combination with ClassVar.

Consider the following example code

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'

which prints 'y' and 'x' as expected.

Now I'd like to make x a ClassVar of type dict:

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

However, now the output is

a.x => {'x': 'x', 'y': 'y'}
b.x => {'x': 'x', 'y': 'y'}

I'd expect that only a.x gets modified and b.x stays at the default init value `{'x': 'x'}.

If the field would not be a ClassVar then I could use the default_factory=dict but that doesn't work in combination with ClassVar since it returns the error

 Field cannot have a default factory
Source Link
wasp256
  • 6.4k
  • 14
  • 78
  • 137

Python dataclass inheritence with class variables

Consider the following example code

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'

which prints 'y' and 'x' as expected.

Now I'd like to make x a ClassVar of type dict:

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

However, now the output is

a.x => {'x': 'x', 'y': 'y'}
b.x => {'x': 'x', 'y': 'y'}

I'd expect that only a.x gets modified and b.x stays at the default init value `{'x': 'x'}.

If the field would not be a ClassVar then I could use the default_factory=dict but that doesn't work in combination with ClassVar.