Как обеспечить соблюдение типов полей класса данных?

В этом коде:

import dataclasses

@dataclasses.dataclass
class MyClass:
    value: str

obj = MyClass(value=1)

создается экземпляр класса данных MyClass со значением, которое не соответствует типу value.

Есть ли простой способ (используя декоратор, аргумент в декораторе dataclass или библиотеку) принудительного применения типов полей, чтобы последняя строка в моем примере вызывала ValueError или что-то в этом роде? Есть ли серьезный недостаток в принудительном использовании типов таким образом?


person Jundiaius    schedule 22.11.2019    source источник
comment
Python не типизирован и не станет типизированным. Если вы хотите использовать проверку типов, попробуйте запустить mypy.   -  person Giacomo Alzetta    schedule 22.11.2019
comment
@Giacomo Это не значит, что вы вообще не можете применять типы во время выполнения…   -  person deceze♦    schedule 22.11.2019
comment
@deceze Это означает, что вы должны реализовать это самостоятельно. ОП специально просил что-то вроде одной строки/переключателя, чтобы включить проверку типов. этого не произойдет.   -  person Giacomo Alzetta    schedule 22.11.2019
comment
Для этой цели я создал крошечную библиотеку Python: github.com/tamuhey/dataclass_utils Эту библиотеку можно применить для такого класса данных, который содержит другой класс данных (вложенный класс данных) и тип вложенного контейнера (например, Tuple[List[Dict...)   -  person Yohei    schedule 08.02.2021


Ответы (1)


Вы можете объявить собственный метод __post_init__ (см. документацию Python) и поместите туда все проверки для принудительной проверки типов. Этот метод можно объявить в родительском классе, чтобы уменьшить количество изменений.

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)

Результаты:

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'>`
person MartenCatcher    schedule 22.11.2019
comment
это проверяет только аннотации текущего класса, а не от родителей. Вместо этого лучше использовать dataclasses.fields - person Joost Döbken; 19.01.2021