Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enforce dataclass fields' types? [duplicate]

In this code:

import dataclasses

@dataclasses.dataclass
class MyClass:
    value: str

obj = MyClass(value=1)

the dataclass MyClass is instantiated with a value that does not obey the value type.

Is there a simple way (using a decorator, an argument in the dataclass decorator or library) of enforcing the fields' types so that the last line in my example raises a ValueError or something like that? Is there a major downside of enforcing types in this way?

like image 476
Jundiaius Avatar asked Nov 22 '19 10:11

Jundiaius


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.

Can 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 __ Post_init __?

The post-init function is an in-built function in python and helps us to initialize a variable outside the __init__ function. post-init function in python.

What does @dataclass do in Python?

Python introduced the dataclass in version 3.7 (PEP 557). The dataclass allows you to define classes with less code and more functionality out of the box.


1 Answers

You can declare a custom __post_init__ method (see python's doc) and put all checks there to force type checking. This method can be declare in parent's class to reduce changes amount.

import dataclasses


@dataclasses.dataclass()
class Parent:
    def __post_init__(self):
        for (name, field_type) in self.__annotations__.items():
            if not isinstance(self.__dict__[name], field_type):
                current_type = type(self.__dict__[name])
                raise TypeError(f"The field `{name}` was assigned by `{current_type}` instead of `{field_type}`")

        print("Check is passed successfully")


@dataclasses.dataclass()
class MyClass(Parent):
    value: str


obj1 = MyClass(value="1")
obj2 = MyClass(value=1)

The results:

Check is passed successfully
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 3, in __init__
  File "<stdin>", line 7, in __post_init__
TypeError: The field `value` was assigned by `<class 'int'>` instead of `<class 'str'>`
like image 196
MartenCatcher Avatar answered Oct 02 '22 07:10

MartenCatcher