LINUX.ORG.RU

DTO в Python

 


1

1

Как можно запретить добавлять новые поля (кроме x и y в примере)?

class MyDTO:
    x: int
    y: str

    def __init__(self, **kwa):
        self.__dict__.update(kwa)

    def __repr__(self):
        return str(self.__dict__)


dto = MyDTO(x=2, z='22') # хотелось бы, чтобы интерпретатор не допустил z из-за отсуствия ее в явно выписанных полях
print(dto) # {'x': 2, 'z': '22'}

Делать

__init__ (self, x: int, y: str)
не хочу, т.к. полей будет очень много и с ними будет путаница.

Ну проверь в конструкторе, что в kwa не прилетает ничего нового.

class MyDTO:
    x: int
    y: str

    def __init__(self, **kwa):
        unknown_fields = kwa.keys() - self.__class__.__annotations__.keys()
        if len(unknown_fields) != 0:
            raise Exception("Unknown fields passed: %s" % unknown_fields)
        self.__dict__.update(kwa)

    def __repr__(self):
        return str(self.__dict__)

kawaii_neko ★★★★
()
Ответ на: комментарий от Aswed

с готовыми транспортными средствами проблем не меньше


import pandas as pd
from pydantic.dataclasses import dataclass

@dataclass
class MyPyDTO:
    x: int
    y: str
    z: pd.DataFrame

py_dto = MyPyDTO(x=1, y='2', z=pd.DataFrame([])) # RuntimeError: no validator found for <class 'pandas.core.frame.DataFrame'>, see `arbitrary_types_allowed` in Config

scientistpython
() автор топика
Ответ на: комментарий от peregrine

а типы dataclass проверяет? или это неправильный датакласс из Питона 3.6?

import pandas as pd
from dataclasses import dataclass

@dataclass(frozen=True)
class MyPyDTO:
    x: int
    y: str
    z: pd.DataFrame

py_dto = MyPyDTO(x='a', y=2, z=pd.DataFrame([]))
print(py_dto)

$ python3.6 dto.py 
MyPyDTO(x='a', y=2, z=Empty DataFrame
Columns: []
Index: [])

scientistpython
() автор топика
Ответ на: комментарий от scientistpython

а типы dataclass проверяет

а в питоне динамическая типизация, надеяться в нём на то что что-то там проверяется нельзя.

peregrine ★★★★★
()
Ответ на: комментарий от scientistpython

Лол ну так тебе же в исключении написано: Сделай в конфиге arbitrary_types_allowed. В чем проблема-то?

@dataclass
class MyPyDTO:
    x: int
    y: str
    z: pd.DataFrame
    class Config:
        arbitrary_types_allowed = True

Aswed ★★★★★
()
Ответ на: комментарий от peregrine

а в питоне динамическая типизация, надеяться в нём на то что что-то там проверяется нельзя

Как же pydantic проводит проверку — задался я вопросом.

fields.py:_apply_validators
    v = validator(cls, v, values, self, self.model_config)
    ...
    return v, None

Кстати, передача ошибки через возвращаемое значение.
Смотрим на какой-нибудь «валидатор»:

def int_validator(v: Any) -> int:
    if isinstance(v, int) and not (v is True or v is False):
        return v

    try:
        return int(v)
    except (TypeError, ValueError):
        raise errors.IntegerError()

И, внезапно, выясняется, что эти валидаторы, на самом деле, просто пересоздают все входные данные. если они еще не являются экземплярами целевого типа. И это, на мой взгляд, есть самый адекватный способ проверки типов в питоне.

Напоминаю, что изменяемые (mutable) типы данных были не более чем оптимизацией ранних компьютеров с малым объемом памяти. Сами базовые типы построены на неизменяемых контейнерах, пересоздаваемых при изменении значения. Однако при этом Гвиде почему-то захотелось императивным с кучей изменяемых по месту типов данных, вроде того же массива — сравните с массивами PHP, которые имеют copy-on-write семантику, нивелирующую кучу граблей, на которые регулярно наступают питонисты.

К слову о массивах, fields.py:_validate_sequence_like

result = []
errors: List[ErrorList] = []
for i, v_ in enumerate(v):
    v_loc = *loc, i
    r, ee = self._validate_singleton(v_, values, v_loc, cls)
    if ee:
        errors.append(ee)
    else:
        result.append(r)
    converted: Union[List[Any], Set[Any], FrozenSet[Any], Tuple[Any, ...], Iterator[Any], Deque[Any]] = result
    ...
    return converted, None

Оно пересоздает заново весь массив, даже если входное значение уже является массивом. Конечно, это менее эффективно, чем copy-on-write и более эффективные варианты персистентных структур данных, но лучше чем питон ничего.

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.