Как избежать повторения литералов в аннотациях типовPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Как избежать повторения литералов в аннотациях типов

Сообщение Anonymous »

Задание: Определите литералы (и их типы для аннотаций функций), но запишите литеральное значение только один раз.
Пример из реальной жизни: Порту может быть назначена VLAN или список VLAN, или он может быть определен как магистральный, или может быть нераспределенным.
Нам нужны константы для «магистрального», «нераспределенного». Определением VLAN является класс VlanId(int): ...
Нам также нужны определения типов для функций аннотирования типов, например:
  • Код: Выделить всё

    get_init_port_value()
    возвращает одну VLAN или «магистраль» (список VLAN или «нераспределенный» список не допускается)
  • Код: Выделить всё

    get_port_status(port)
    возвращает текущие выделения на данном порту
Попытка 1: Определение константных значений и типов отдельно. Работает, но некрасиво.

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

Trunk = Literal["trunk"]
TRUNK = "trunk"  # TRUNK type becomes Literal[“trunk”]
# NB, TRUNK: Trunk = “trunk” provides the exact same thing.
Unallocated = Literal["unallocated"]
UNALLOCATED = "unallocated"  # UNALLOCATED type becomes Literal[“unallocated”]
PortVlanAllocation = VlanId | list[VlanId] | Trunk | Unallocated
def get_init_port_value() -> VlanId | Trunk: ...
def get_port_status(port: Port) -> PortVlanAllocation: ...
Попытка 2: Использование типа Final. Как и Try1, он работает, но некрасиво. А Type по-прежнему не работает, как и Try3.

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

..
TRUNK: Final = "trunk"  # TRUNK type becomes Literal[“trunk”]
..
Попытка 3: Получение типов из определенных констант. Не работает, поскольку Type может определить только тип класса.

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

..
PortVlanAllocation = VlanId | list[VlanId] | Type[TRUNK] | Type[UNALLOCATED]
..
Попытка 4: Еще раз получить типы из определенных констант. Не работает, поскольку Literal не принимает TRUNK и UNALLOCATED, даже если они являются литералами.

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

..
PortVlanAllocation = VlanId | list[VlanId] | Literal[TRUNK] | Literal[UNALLOCATED]
..
Попытка 5: Используйте enum для выделений, не относящихся к VLAN. Работает, достигается то, что литеральная строка записывается только один раз и компактна, но может быть не лучшим вариантом.

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

class NonVlanAlloc(enum.Enum):
TRUNK = "trunk"
UNALLOCATED = "unallocated"
PortVlanAllocation = NonVlanAlloc | VlanId | list[VlanId]
def get_init_port_value() -> Literal[NonVlanAlloc.TRUNK] | VlanId: ...
Я говорю, что это работает, поскольку mypy предоставляет ожидаемые результаты для следующих допустимых и недействительных операторов возврата get_init_port_value:

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

return NonVlanAlloc.UNALLOCATED # Incompatible return value type (got "Literal[NonVlanAlloc.UNALLOCATED]", expected "Union[Literal[NonVlanAlloc.TRUNK], VlanId]")
return "trunk"  # Incompatible return value type (got "Literal['trunk']", expected "Union[Literal[NonVlanAlloc.TRUNK], VlanId]")
return NonVlanAlloc.TRUNK  # OK
return 42  # Incompatible return value type (got "Literal[42]", expected "Union[Literal[NonVlanAlloc.TRUNK], VlanId]")
return VlanId(2345789789)  # OK
Это решение с перечислением кажется приемлемым, но что, если у нас нет UNALLOCATED? Определение перечисления для одного TRUNK было бы излишним, не так ли?
Интересно, есть ли способ получить тип TRUNK (без отдельного явного определения) , то есть то, чего я хотел достичь в Try3 и Try4 (и вроде как достиг в Try5). Это противоположно получению литерала из типа Literal в Python во время выполнения?, потому что
  • они объявляют типы и определяют значения,

    li>
    пока я объявляю значения (константы) и выясняю их типы (например, для аннотаций функций).


Подробнее здесь: https://stackoverflow.com/questions/763 ... nnotations
Реклама
Ответить Пред. темаСлед. тема

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

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