Как условно ограничить типы Union в Python?Python

Программы на Python
Ответить
Anonymous
 Как условно ограничить типы Union в Python?

Сообщение Anonymous »

Задача проверки типов для AmiNode
У меня возникла интересная задача при анализе файлов *.ami.
Я использую следующий рекурсивный тип с произвольной глубиной иерархии:
AmiName = NewType("AmiName", str)
AmiAtom: TypeAlias = bool | int | float | str
AmiExpr: TypeAlias = "'AmiAtom' | 'AmiNode'"
AmiNode: TypeAlias = tuple[AmiName, list[AmiExpr]]

Теперь правила грамматики для файлов *.ami написаны таким образом, что, когда первый элемент этого термина list[AmiExpr] является AmiAtom, в отличие от AmiNode, все остальные элементы термина list[AmiExpr] также должны быть AmiAtom.
Однако мои определения типов, приведенные выше, не обеспечивают соблюдения это грамматическое правило.
(Мой синтаксический анализатор применяет это правило, но на уровне значения, что означает, что нарушения должны отмечаться во время выполнения с помощью исключений.
Я хотел бы отмечать нарушения во время проверки типа.)
Одна функция, использующая тип AmiNode, определяется следующим образом:
src/pybert/models/bert.py:
339 def get_numeric_values(prefix: AmiName, node: AmiNode) -> dict[AmiName, list[float]]:
340 "Retrieve all numeric values from an AMI node, encoding hierarchy in key names."
341
{snip}
348 pname = node[0]
349 vals = node[1]
350 pname_hier = AmiName(prefix + pname)
351 first_val = vals[0]
352 if isnumeric(first_val):
353 return {pname_hier: list(map(float, vals))}
{snip}

Функция вызывает себя рекурсивно, углубляясь в иерархию узлов, пока не достигнет дна, ожидая найти там список чисел с плавающей запятой, который она возвращает.
Она проверяет достижение дна, анализируя первое значение в списке AmiExpr, чтобы увидеть, является ли оно числовым (одна возможная конкретная альтернатива для типа union: AmiAtom).
As Как упоминалось выше, грамматические правила для файлов *.ami требуют, чтобы если первое значение в списке — AmiAtom, то такими же должны быть и все остальные.
(Правило на самом деле немного более строгое, поскольку если первое значение числовое, то такими же должны быть и все остальные.)
В результате дыры в определениях типов выше я получаю следующую ошибку от mypy (проверка типов Python), когда он сканирует эту функцию:
src/pybert/models/bert.py:353: error: Argument 1 to "map" has incompatible type "type[float]"; expected "Callable[[int | float | str | AmiNode], float]" [arg-type]

Пояснение приведенного выше сообщения об ошибке из mypy:
  • Аргумент 1 для «map» — это стандартная функция приведения типов Python: float.
    (Идея состоит в том, что float применяется ко всем элементам списка vals.)
  • Сигнатура типа Python: Callable[[int | плавать | ул | AmiNode], float], описывает функцию, аргумент которой должен быть одним из: int, float, str или AmiNode и которая возвращает число с плавающей запятой.
  • Нотация Python: {: создает экземпляр словаря (типа dict) только с одной парой ключ/значение.
Итак, проблема, с которой сталкивается проверка типов, заключается в том, что я пытаюсь применить функцию float к каждому элементу в списке AmiExpr, но тип AmiExpr не гарантированно будет числовым, как того требует float.
Что я могу добавить к своим определениям типов, чтобы заполнить эту дыру и создать проверку типов? счастлив?


Подробнее здесь: https://stackoverflow.com/questions/798 ... -in-python
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

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