create dataclass with optional attribute

Question:

I’m trying create dataclass with optional attribute is_complete:

from dataclasses import dataclass
from typing import Optional


@dataclass(frozen=True)
class MyHistoricCandle:
    open: float
    high: float
    low: float
    close: float
    volume: int
    time: datetime
    is_complete: Optional[bool]

But when i init MyHistoricCandle object without is_complete attribute:

MyHistoricCandle(open=1, high=1, low=1, close=1, volume=1, time=datetime.now())

Getting this error:

TypeError: MyHistoricCandle.__init__() missing 1 required positional argument: 'is_complete'

Question: Is it even possible to create dataclass with optional attribute? I tried
is_complete: Optional[bool] = None , but sometimes i don’t want add this field instead of setting None value

Asked By: 555Russich

||

Answers:

By using dataclass, you are committing to a certain level of rigor regarding the interface to your class. All instances of MyHistoricCandle should have an is_complete attribute, not just some. If you don’t want that to be the case, you should probably define two separate classes, one with the attribute and one without.

But, you can work around it by not declaring is_complete as a field, but as an explicit attribute initialized by an init-only variable with a default value of None.

from dataclasses import dataclass, InitVar


@dataclass(frozen=True)
class MyHistoricCandle:
    open: float
    high: float
    low: float
    close: float
    volume: int
    time: datetime
    is_complete: InitVar[Optional[bool]] = None

    def __post_init__(self, is_complete):
        if is_complete is not None:
            self.is_complete = is_complete

As is_complete is not a field, it will be your responsibility to override any of the autogenerated methods (__repr__, __eq__, etc) to take into account the value of self.is_complete.



(Below is a previous answer, when I thought the question was about providing a default value for the attribute when none was passed to __init__.)

TL;DR The type does not make an attribute optional; the presence of a default value does.


dataclass doesn’t use the specified type for anything*, much less infer a default value for the field if you don’t supply an argument when constructing the value. If you want to omit is_complete from the call, you need to specify what value should be used in its place, whether that value be True, False, or None.

@dataclass(frozen=True)
class MyHistoricCandle:
    open: float
    high: float
    low: float
    close: float
    volume: int
    time: datetime
    is_complete: Optional[bool] = None

* With the exception of InitVar and ClassVar.

Answered By: chepner