Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python dataclasses: What type to use if __post_init__ performs type conversion?

I have a Python class, with a field which can be passed one of several sequence types. To simplify I'll stick with tuples and lists. __init__ converts the parameter to MyList.

from typing import Union
from dataclasses import dataclass, InitVar, field

class MyList(list):
    pass

@dataclass
class Struct:
    field: Union[tuple, list, MyList]

    def __post_init__(self):
        self.field = MyList(self.field)

What type should I use for the field declaration?

  • If I supply a union of all possible input types, the code does not document that field is always a MyList when accessed.
  • If I only supply the final MyList type, PyCharm complains when I pass Struct() a list.

I could instead use:

_field: InitVar[Union[tuple, list, MyList]] = None
field: MyList = field(init=False)

def __post_init__(self, _field):
    self.field = MyList(_field)

but this is tremendously ugly, especially when repeated across 3 fields. Additionally I have to construct a struct like Struct(_field=field) instead of Struct(field=field).

In April 2018, "tm" commented on this issue on PyCharm's announcement: https://blog.jetbrains.com/pycharm/2018/04/python-37-introducing-data-class/#comment-323957

like image 509
nyanpasu64 Avatar asked Aug 08 '18 02:08

nyanpasu64


People also ask

What is __ Post_init __ in python?

Python - __post_init__ method in Dataclasses You can use __post_init__ on classes decorated with dataclass to add custom logic on init.

What is the use of Dataclasses in python?

dataclass module is introduced in Python 3.7 as a utility tool to make structured classes specially for storing data. These classes hold certain properties and functions to deal specifically with the data and its representation.

Can python Dataclasses have methods?

A dataclass can very well have regular instance and class methods. Dataclasses were introduced from Python version 3.7. For Python versions below 3.7, it has to be installed as a library.

How to use Python dataclasses?

How to use Python dataclasses 1 Python dataclass example. ... 2 Customize Python dataclass fields with the field function. ... 3 Use __post_init__ to control Python dataclass initialization. ... 4 Use InitVar to control Python dataclass initialization. ... 5 When to use Python dataclasses — and when not to use them. ...

What is an init-only field in Python?

If a field is an InitVar, it is considered a pseudo-field called an init-only field. As it is not a true field, it is not returned by the module-level fields () function. Init-only fields are added as parameters to the generated __init__ () method, and are passed to the optional __post_init__ () method.

What is class_or_instance in Python?

dataclasses. fields (class_or_instance) ¶ Returns a tuple of Field objects that define the fields for this dataclass. Accepts either a dataclass, or an instance of a dataclass. Raises TypeError if not passed a dataclass or instance of one.

How to turn a dataclass into a dictionary in Python?

The idea would be that you need to pull in your old PlayCards from persistence data. Maybe there is a better best practice for that. You can turn a dataclass into a dictionary with the dataclass.asdict function. Most python wrappers to data storage backends accept dictionaries.


1 Answers

You are conflating assigning a value to the attribute with the code that produces the value to assign to the attribute. I would use a separate class method to keep the two pieces of code separate.

from dataclasses import dataclass


class MyList(list):
    pass


@dataclass
class Struct:
    field: MyList

    @classmethod
    def from_iterable(cls, x):
        return cls(MyList(x))


s1 = Struct(MyList([1,2,3]))
s2 = Struct.from_iterable((4,5,6))

Now, you only pass an existing value of MyList to Struct.__init__. Tuples, lists, and whatever else MyList can accept are passed to Struct.from_iterable instead, which will take care of constructing the MyList instance to pass to Struct.

like image 157
chepner Avatar answered Nov 14 '22 22:11

chepner