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?
field
is always a MyList
when accessed.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
Python - __post_init__ method in Dataclasses You can use __post_init__ on classes decorated with dataclass to add custom logic on init.
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.
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 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. ...
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.
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.
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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With