Search code examples
pythonpython-dataclasses

Passing arguments in dataclass representation


I have a below NormalClass that I want to structure as a dataclass. However I was not sure how I can pass the date_str param without __init__ in the dataclass. Any thoughts?

class FieldDateTime():
    def __init__(self, data, d_format='%m/%d/%y %I:%M %p'):
        try:
            self.data = datetime.strptime(data, d_format)
        except ValueError as e:
            raise ValueError('Dateformat incorrect')

    def __call__(self):
        return self.data

class NormalClass:
    def __init__(self, id, date_str):
        self.id: int = id
        self.dt: FieldDateTime = FieldDateTime(date_str)

@dataclass
class DataClassObj:
    id: int
    dt: FieldDateTime(date_str) 

How do I pass the date_str as an argument in the data class representation (DataClassObj) without the init?


Solution

  • Your question has to be more detailed, but I think this is what you're looking for:

    from __future__ import annotations
    
    from datetime import datetime
    from dataclasses import dataclass, InitVar, field
    
    
    class FieldDateTime:
        def __init__(self, data, d_format='%m/%d/%y %I:%M %p'):
            try:
                self.data = datetime.strptime(data, d_format)
            except ValueError as e:
                raise ValueError('Dateformat incorrect')
    
        def __repr__(self):
            return f"{self.__class__.__name__}({self.data})"
    
        def __call__(self):
            return self.data
    
    
    @dataclass
    class NormalDataClass:
        id: int
        date_str: InitVar[str]
        dt: FieldDateTime = field(init=False)
    
        def __post_init__(self, date_str):
            self.dt = FieldDateTime(date_str)
    
    
    print(NormalDataClass(10, '09/04/21 08:11 PM'))
    

    output (given the dataclass-like __repr__ implementation on FieldDateTime to make it look a bit better):

    NormalDataClass(id=10, dt=FieldDateTime(2021-09-04 20:11:00))
    

    from doc:

    Init-only fields are added as parameters to the generated __init__ method, and are passed to the optional __post_init__ method.

    So we can use InitVar for our date_str and pass it to __post_init__ to create our FieldDateTime object.