Skip to content
Advertisement

Python main data class and dependent class below (in term of physical code)

Let’s say I have such structure with @dataclass

from dataclasses import dataclass, field
from dataclasses_json import dataclass_json

@dataclass_json
@dataclass()
class Direction:
    x: int
    y: int
    z: int

@dataclass_json
@dataclass()
class Movement:
    speed: int
    direction: Direction = field(default_factory=Direction)

movementDict = {'speed':2,'direction': {'x':0,'y':0,'z':1}}
movement = Movement.from_dict(movementDict)
print(movement)

It does what I want – transfering raw dictionary into class object. However I am forced to make Direction class on top of the file. It would be more readable if Movement class was on top of the code. Is there any way to achieve this? If I switch both these classes I get

NameError: name ‘Direction’ is not defined

Advertisement

Answer

One option could be to create a lambda and pass it as the default_factory argument. I would also either add a from __future__ import annotations import at the top, or else wrap the annotation for the forward-declared class in a string, just so the compiler doesn’t complain about a similar NameError in this case.

This works because the type (Direction) is only evaluated once the lambda is actually called. If you don’t believe me, you can also try making an intentional typo in the name – for example like lambda: Drection(0, 0, 0) and will note that the code still compiles fine even though that name is not defined, as long as your input dict object has a value for the ‘direction’ key.

Here’s an example to illustrate that below:

from dataclasses import dataclass, field
from dataclasses_json import dataclass_json


@dataclass_json
@dataclass()
class Movement:
    speed: int
    direction: 'Direction' = field(default_factory=lambda: Direction(0, 0, 0))


@dataclass_json
@dataclass()
class Direction:
    x: int
    y: int
    z: int


movementDict = {'speed': 2}
movement = Movement.from_dict(movementDict)
print(movement)

Result:

Movement(speed=2, direction=Direction(x=0, y=0, z=0))

Side note: just adding a plug here to a very similar de-serialization library I’ve been working on, called the dataclass-wizard. It has pretty minimal dependencies, and performs a little better on average, in case anyone is curious and wants to check it out.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement