Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force type conversion in python dataclass __init__ method

I have the following very simple dataclass:

import dataclasses  @dataclasses.dataclass class Test:     value: int 

I create an instance of the class but instead of an integer I use a string:

>>> test = Test('1') >>> type(test.value) <class 'str'> 

What I actually want is a forced conversion to the datatype i defined in the class defintion:

>>> test = Test('1') >>> type(test.value) <class 'int'> 

Do I have to write the __init__ method manually or is there a simple way to achieve this?

like image 666
johnson Avatar asked Feb 25 '19 09:02

johnson


People also ask

Does Dataclass enforce type?

Data classes also make it easier to create frozen (immutable) instances, serialize instances and enforce type hints usage. The main parts of a data class are: @dataclass decorator which returns the same defined class but modified. field function which allow for per-field customizations.

What is Dataclass 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. DataClasses in widely used Python3.6.

Can python Dataclass 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.

What is @dataclass?

A data class is a class typically containing mainly data, although there aren't really any restrictions. It is created using the new @dataclass decorator, as follows: from dataclasses import dataclass @dataclass class DataClassCard: rank: str suit: str.


1 Answers

The type hint of dataclass attributes is never obeyed in the sense that types are enforced or checked. Mostly static type checkers like mypy are expected to do this job, Python won't do it at runtime, as it never does.

If you want to add manual type checking code, do so in the __post_init__ method:

@dataclasses.dataclass class Test:     value: int      def __post_init__(self):         if not isinstance(self.value, int):             raise ValueError('value not an int')             # or self.value = int(self.value) 

You could use dataclasses.fields(self) to get a tuple of Field objects which specify the field and the type and loop over that to do this for each field automatically, without writing it for each one individually.

def __post_init__(self):     for field in dataclasses.fields(self):         value = getattr(self, field.name)         if not isinstance(value, field.type):             raise ValueError(f'Expected {field.name} to be {field.type}, '                              f'got {repr(value)}')             # or setattr(self, field.name, field.type(value)) 
like image 136
deceze Avatar answered Oct 22 '22 05:10

deceze