Как безопасно ввести функцию, которая принимает класс контейнера Generic, в Python?Python

Программы на Python
Anonymous
Как безопасно ввести функцию, которая принимает класс контейнера Generic, в Python?

Сообщение Anonymous »

Код: Выделить всё

from __future__ import annotations

from datetime import datetime, UTC
from typing import Any, Generic, Self, TypeVar

from pydantic import AwareDatetime, BaseModel

EventDataT_co = TypeVar('EventDataT_co', covariant=True)

class Event(BaseModel, Generic[EventDataT_co]):
raised_at: AwareDatetime
data: tuple[EventDataT_co, ...]

@classmethod
def from_data(cls, *data: EventDataT_co) -> Self:
return cls(raised_at=datetime.now(UTC), data=data)

def save_events(*events: Event): ...  # not type-safe (someone might make unsafe assumption on `.data`)
def save_events(*events: Event[Any]): ...  # same
def save_events(*events: Event[object]): ...  # Only allowed if Event is covariant, but then I can't have a custom constructor
def save_events(*events: Event[EventDataT_co]): ...  # It implies this is a generic function, when it's more `.data`-agnostic
Mypy выдает ошибку: невозможно использовать переменную ковариантного типа в качестве параметра [misc] в строке конструктора def from_data(...).
Я понятия не имею, как это решить. Признаюсь, я новичок в концепции дисперсии, и мне неясно, делаю ли я что-то не так (является ли Event даже ковариантным с самого начала), или mypy нет позволяя что-то, что должно. Я стараюсь избегать использования Any здесь, потому что save_events на самом деле является методом другого класса, который может быть подклассом, и я бы не хотел, чтобы разработчик, который наследует от него, был укушен моим использование Any. Событие[object] кажется самым безопасным, но оно требует ковариации. Это не только означает отсутствие специального конструктора (я думаю), но также означает фактическую ковариацию, и я не уверен, что мой класс событий является ковариантным за пределами этого конкретного использования с объектом (т.е.: я не вижу использования случай, когда функция handle_foo_created(event: Event[FooParent]) должна когда-либо принимать Event[FooChild], и я не думаю, что событие: FooParentEvent = FooParentEvent.from_data(FooChild()) является вариант использования, который я хочу поддержать, но возможно, что и здесь я ошибаюсь).


Подробнее здесь: https://stackoverflow.com/questions/786 ... s-in-pytho

Вернуться в «Python»