модуль ввода — строковый литеральный тип

Я использую новый модуль Python 3.5 typing, и он был радостным.

Мне было интересно, как можно указать тип на основе точного строкового литерала. Например, функция гарантированно возвращает одну из четырех строк — «Север», «Запад», «Восток», «Юг» — как мы можем выразить это как переменную определенного типа, а не просто str.

Я просмотрел документацию, нашел тип Union и функцию TypeVar, но не смог найти ответ.

Пример функции, выражающей эту проблему:

def compute_quadrant(x: int, y: int) -> str:
    if x > 0 and y > 0:
        return 'I'
    elif x < 0 and y > 0:
        return 'II'
    elif x < 0 and y < 0:
        return 'III'
    elif x > 0 and y < 0:
        return 'IV'

Вместо того, чтобы просто возвращать str, я хотел бы вернуть более конкретный тип, который является одним из четырех значений — "I", "II", "III" или "IV".

В Typescript можно сделать: type Quadrant = "I" | "II" | "III" | "IV" — есть ли хороший сахар Python для этого варианта использования с модулем typing?


person fructosewizard    schedule 05.10.2016    source источник
comment
Между прочим, есть обсуждение добавления типов, представляющих всего несколько конкретных значений. Но, конечно, в этом случае в этом нет необходимости, так как enum подходит идеально.   -  person max    schedule 17.04.2017


Ответы (1)


Не обращая внимания на модуль typing, о котором вы спрашивали, одним из решений вашей проблемы может быть использование Enum, как предполагается в нескольких комментариях. Код для этого будет выглядеть так:

from enum import Enum

class Quadrant(Enum):
    I = 1
    II = 2
    III = 3
    IV = 4

def compute_quadrant(x: int, y: int) -> Quadrant:
    if x > 0 and y > 0:
        return Quadrant.I
    elif x < 0 and y > 0:
        return Quadrant.II
    elif x < 0 and y < 0:
        return Quadrant.III
    elif x > 0 and y < 0:
        return Quadrant.IV
    # return None  # this is what happens without an else clause!

if __name__ == "__main__":
    quad = compute_quadrant(1, -1)
    print(quad, type(quad))              # -> Quadrant.IV <enum 'Quadrant'>
    print(quad.name, type(quad.name))    # -> IV <class 'str'>
    print(quad.value, type(quad.value))  # -> 4 <class 'int'>

Как видите, вы можете использовать имя и значение Enums. Имя — это одна из строк, которые вы запросили.

Одна проблема, которую я вижу здесь, - это отсутствующее предложение else в функции и текущее поведение mypy, принимающее None в качестве допустимого возвращаемого значения для Quadrant. Это должно обрабатываться вручную.

person Lukisn    schedule 17.03.2017