2

When you provide a default for anInitVar typed variable in a dataclass, the attributefor that variable is set (actually, for variables that lack a default the attribute seems to beactively deleted indataclasses:_process_class()).

from dataclasses import dataclass, InitVar, fields@dataclassclass HasDefault:    abc: int = 18    xyz: InitVar[str] = 'oops'    def __post_init__(self, xyz):        self.abc += len(xyz)@dataclassclass NoHasDefault:    abc: int    xyz: InitVar[str]    def __post_init__(self, xyz):        self.abc += len(xyz)hd = HasDefault(abc=42, xyz='so long...')print('field names', [field.name for field in fields(hd)])print(hd, hd.abc, hd.xyz)print()hd2 = HasDefault(abc=42)print('field names', [field.name for field in fields(hd2)])print(hd2, hd2.abc, hd2.xyz)print()hd3 = HasDefault()print('field names', [field.name for field in fields(hd3)])print(hd3, hd3.abc, hd3.xyz)print()nhd = NoHasDefault(abc=42, xyz='so long...')print('field names', [field.name for field in fields(nhd)])print(nhd, getattr(nhd, 'xyz', 'no attribute xyz'))

which gives:

field names ['abc']HasDefault(abc=52) 52 oopsfield names ['abc']HasDefault(abc=46) 46 oopsfield names ['abc']HasDefault(abc=22) 22 oopsfield names ['abc']NoHasDefault(abc=52) no attribute xyz

Why is the attributexyz setat all forInitVar typed variables (when there is a default)? I expected this attribute never to be set as it is only for initialisation. Is this a bug?

mypy actually complains that those instances have no attributexyz, so it seems to handleInitVar differently.

Because of this I needed to add some extra lines to get loading such adataclassfrom YAML to work in the same way, as normally the value from the YAML mappingwould be used to set the attribute, instead of the default. So what you can do (in `ruamel.yaml>0.17.34) is:

from dataclasses import dataclass, InitVarfrom typing import ClassVarfrom ruamel.yaml import YAMLyaml = YAML()@yaml.register_class@dataclassclass HasDefault:    yaml_tag: ClassVar = '!has_default'  # if not set the class name is taken ('!HasDefault')    abc: int    xyz: InitVar[str] = 'oops'    def __post_init__(self, xyz):        self.abc += len(xyz)yaml_str = """\!has_defaultabc: 42xyz: hello world"""data = yaml.load(yaml_str)print(data, data.xyz == 'oops')

giving:

HasDefault(abc=53) True

otherwisedata.xyz would equalhello world

askedOct 4, 2023 at 9:32
Anthon's user avatar

0

Know someone who can answer? Share a link to thisquestion viaemail,Twitter, orFacebook.

Your Answer

Sign up orlog in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to ourterms of service and acknowledge you have read ourprivacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.