Принудительное преобразование типов в классе данных Python __init__ метод - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть следующий очень простой класс данных:

import dataclasses

@dataclasses.dataclass
class Test:
    value: int

Я создаю экземпляр класса, но вместо целого я использую строку:

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

Что я на самом деле хочутакое принудительное преобразование в тип данных, определенный в определении класса:

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

Нужно ли писать метод __init__ вручную или есть простой способ добиться этого?

Ответы [ 3 ]

0 голосов
/ 25 февраля 2019

Этого можно добиться, используя метод __post_init__:

import dataclasses

@dataclasses.dataclass
class Test:
    value : int

    def __post_init__(self):
        self.value = int(self.value)

Этот метод вызывается по методу __init__

https://docs.python.org/3/library/dataclasses.html#post-init-processing

0 голосов
/ 11 апреля 2019

Да, простой ответ - просто сделайте преобразование самостоятельно в своем __init__().Я делаю это потому, что хочу, чтобы мои объекты frozen=True.

Для проверки типа, Pydandic заявляет, что делает это, но я еще не пробовал: https://pydantic -docs.helpmanual.io/

0 голосов
/ 25 февраля 2019

Подсказка типа атрибутов класса данных никогда не выполняется в том смысле, что типы принудительно применяются или проверяются.Ожидается, что в основном статические проверки типа, такие как mypy , будут выполнять эту работу, Python не будет делать это во время выполнения, как никогда.

Если вы хотите добавить код проверки типа вручную, выполнитепоэтому в методе __post_init__:

@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)

Вы можете использовать dataclasses.fields(self), чтобы получить кортеж из Field объектовкоторые определяют поле, тип и цикл, чтобы сделать это для каждого поля автоматически, без записи его для каждого отдельно.

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))
...