dataclass requiring a value after being defined as Optional

Question:

In the snippet below, I can’t understand why I need to explicitly provide a value for the TimeCollection. How do I set this up so the line becomes plan1 = TimeCollection()

from __future__ import annotations
from dataclasses import dataclass
import datetime
from typing import Optional, List

@dataclass
class Event():
    event_type: str
    event_date: datetime.datetime

@dataclass
class Timeline():
    name: str
    events: List[Event]
    linked_timeline: Optional[Timeline]
        
@dataclass
class TimelineCollection():
    timelines: Optional[List[Timeline]]
    def add(self, tl:Timeline) -> None :
        self.timelines.append(tl)
        

plan1 = TimelineCollection([])
app2_tl = Timeline(name="APP2", events=[], linked_timeline=None)
plan1.add(app2_tl)
app1_tl = Timeline(name="APP1", events=[
    Event(event_type="Replace Attempt Scheduled", event_date=datetime.datetime(2022, 3, 31)),
    Event(event_type="Replace Attempt Successful", event_date=datetime.datetime(2023, 1, 1)),
    Event(event_type="Replaced", event_date=datetime.datetime(2023, 1, 1))],
    linked_timeline=app2_tl
)
plan1.add(app1_tl)
Asked By: user2302244

||

Answers:

Note that Optional might not be the correct annotation in this case. Optional[T] is equivalent to T | None in the new style annotations, which implies that the value might be either of type T, or an explicit None value.

In the scope of dataclasses, fields annotated as Optional[T] would ideally be assigned a default value of None, for instance such as:

field: T | None = None

I note that in your case, it appears you are instantiating plan1 using:

plan1 = TimelineCollection([])

This implies that the default value for the timelines field should actually be an empty list.

This can then by accomplished with field(default_factory=...) as shown below. Setting a default value is not recommended since the type is list, which is a mutable type in Python.

from __future__ import annotations
from dataclasses import dataclass, field

@dataclass
class TimelineCollection:
    timelines: list[Timeline] = field(default_factory=list)

plan1 = TimelineCollection()
print(plan1)

Prints:

TimelineCollection(timelines=[])
Answered By: rv.kvetch