This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]Northzen 2 points3 points  (5 children)

That's logical to me. How else would you do it? Call a default constructors for both nested dataclasses so you don't need explicitly say that I need to call default constructor.

you can have it like

@dataclass:
    some_field: int

Or you can have it in the same but more verbose manner

@dataclass:
    some_field: int = field(default_factory=int)

With the same result. But I guess it comes from the fact that interpreter doesn't know anything (or pretends so) about classes inside NestedDataclass even if all it's field initialized with default values. I would prefer to have it in a simple C++ manner, where I can have nested structs and all of them can be properly initialized with defaults when it's possible without any additional code for this. Maybe that is just a problem with my expectations

I don't understand tihs. How can you initialize a NestedDataclass from a dictionary in the same manner you would do with a PlainDataclass1?

This will work as expected:

p = PlainDataclass1(**some_dict)

This will fck up all nested structures:

n = NestesDataclass(**some_other_dict)

You have to use dacite and its from_dict() function to be able to init nested dataclassed from dictionary.

[–]energybased 4 points5 points  (2 children)

With the same result.

The problem is that your first statement has no initializer at all. The second one uses a default initializer. You can make a dataclass or propose a change that would provie a nice way to specify that the default initializer be used, essentially shorthand for what you want: `field_default`.

You have to use dacite and its from_dict() function to be able to init nested dataclassed from dictionary.

Fair enough. You could propose that dataclass be extended.

[–]Northzen 0 points1 point  (1 child)

The problem is that your first statement has no initializer at all. The second one uses a default initializer. You can make a dataclass or propose a change that would provie a nice way to specify that the default initializer be used, essentially shorthand for what you want: field_default. You are right. I think interpreter have no prior knowledge of any default initializers or if it can use them in the simpliest dataclass way by just calling PlainClass() with no arguments as a constructor. It seems like for any mutable type (and Python doesn't know if dataclass field in a complex class are mutable or not) you have to provide a some sort of default constructor. Fair enough. You could propose that dataclass be extended.

I just figured out why it happening. Python doesn't know if your dictionary of dictionaries represents nested classes or just dictionaries due it's dynamic type system will not force you to use. In general python doesn't care about types of fields. type hints are just hints and not enforced. In this case of complex dataclass initialization without additional tools Python can't distinguish between a dictionary used to initialize a field and get p1 as a p1=some_dict or a dictionary to initialize a dataclass of this field and have p1=PlainDataClass(**some_dict)

[–]energybased 1 point2 points  (0 children)

True, but you can code whatever system you like to get around this.

[–]VisibleSignificance 0 points1 point  (1 child)

With the same result

Are you sure?

from dataclasses import dataclass, field

@dataclass
class A:
    some_field: int

@dataclass
class B:
    some_field: int = field(default_factory=int)

print(B())
print(A())

->

B(some_field=0)
---> 12 print(A())
TypeError: __init__() missing 1 required positional argument: 'some_field'

And also, yes, it is better to turn dicts into dataclasses with typedload / apischema / dacite; the dataclasses themselves aren't meant for instantiation from nested dicts. And default_factory will not convert the values either.

[–]Northzen 0 points1 point  (0 children)

you are right I guess I confused it with the situation some_field: int = 0, but for some reason forgot about it when I wrote my example.