Код: Выделить всё
typing.LiteralКод: Выделить всё
# GOOD
from enum import Enum, auto
class Foo(Enum):
X = auto()
Y = auto()
lookup: dict[Foo, str] = {Foo.X: "cool", Foo.Y: "whatever"}
print(lookup[Foo.X])
Например, это отлично передает mypy --strict, но не выполняется во время выполнения, потому что мы «забыли» обновить сам поиск:
Код: Выделить всё
# BAD
from enum import Enum, auto
class Foo(Enum):
X = auto()
Y = auto()
Z = auto() # NEW
lookup: dict[Foo, str] = {Foo.X: "cool", Foo.Y: "whatever"}
print(lookup[Foo.Z]) # CHANGED
- Можно ли его аннотировать текущими подсказками типов Python как общий тип для любого Enum или Literal[ ...] тип ключа? (Например, синтаксис в лучшем случае, на который мы надеемся: поиск: ExhaustiveDict[Foo, str] = {... или поиск: ExhaustiveDict[Literal[1, 2], str] = {1: "a", 2: "b".)
- Если нет, можно ли это сделать для конкретной пары типов ключ/значение? (Например, разумным синтаксисом может быть поиск: ExhaustiveDictFooTo[str] = {...} и/или поиск: ExhaustiveDictFooToStr = {...}, если определение этих типов разумно.)
Дополнительные примечания для справки/чтобы было ясно, что мы понимаем:
- В настоящее время мы используем обходной путь исчерпывающих операторов if, но переход от компактного dict к компактному раздражает. вся функция:
Если Foo позже будет изменен на включение Z, мы получим ошибку в последней строке, например, аргумент 1 «исчерпывающий» имеет несовместимый тип «Literal[Foo.Z]» "; ожидалось "NoReturn", что означает, что мы не обработали этот случай ранее в if (сообщение не сразу очевидно, но в конечном итоге оно просто соответствует шаблону того, что оно означает, и намного лучше, чем ничего). (Предположительно, здесь также можно использовать match/
Код: Выделить всё
from typing import NoReturn def exhaustive(val: NoReturn) -> NoReturn: raise NotImplementedError(val) def lookup(val: Foo) -> str: if val is Foo.X: return "cool" elif val is Foo.Y: return "whatever" else: exhaustive(val), но мы все еще используем Python 3.9, а не 3.10.)Код: Выделить всё
case - Это одинаково хорошо применимо и к использованию Literal[1, 2, 3] или Literal[ "foo", "bar", "baz"] в качестве типа ключа в дополнение к enum.Enum.
- Это несколько перекрывается с набором текста .TypedDict и его значение total=True по умолчанию, но AFAICT ограничено строковыми ключами, записанными буквально в определении TypedDict (поэтому нам нужно будет преобразовать перечисления в строки и иметь дополнительную функциональность который проверяет, что определение TypedDict действительно соответствует перечислению).
- По сути, я спрашиваю, как написать Python, эквивалентный типу TypeScript Record, что-то вроде Record[ Foo, str] или Record[Literal["foo", "bar"], str] (эквивалент Record в Typescript) .
Подробнее здесь: https://stackoverflow.com/questions/720 ... teral-keys