|
| 1 | +.. _literal_types: |
| 2 | + |
| 3 | +Literal types |
| 4 | +============= |
| 5 | + |
| 6 | +.. note:: |
| 7 | + |
| 8 | + Literal is an officially supported feature, but is highly experimental |
| 9 | + and should be considered to be in alpha stage. It is very likely that future |
| 10 | + releases of mypy will modify the behavior of literal types, either by adding |
| 11 | + new features or by tuning or removing problematic ones. |
| 12 | + |
| 13 | +Literal types let you indicate that an expression is equal to some specific |
| 14 | +primitive value. For example, if we annotate a variable with type ``Literal["foo"]``, |
| 15 | +mypy will understand that variable is not only of type ``str``, but is also |
| 16 | +equal to specifically the string ``"foo"``. |
| 17 | + |
| 18 | +This feature is primarily useful when annotating functions that behave |
| 19 | +differently based on the exact value the caller provides. For example, |
| 20 | +suppose we have a function ``fetch_data(...)`` that returns ``bytes`` if the |
| 21 | +first argument is ``True``, and ``str`` if it's ``False``. We can construct a |
| 22 | +precise type signature for this function using ``Literal[...]`` and overloads: |
| 23 | + |
| 24 | +.. code-block:: python |
| 25 | +
|
| 26 | + from typing import overload, Union |
| 27 | + from typing_extensions import Literal |
| 28 | +
|
| 29 | + # The first two overloads use Literal[...] so we can |
| 30 | + # have precise return types: |
| 31 | +
|
| 32 | + @overload |
| 33 | + def fetch_data(raw: Literal[True]) -> bytes: ... |
| 34 | + @overload |
| 35 | + def fetch_data(raw: Literal[False]) -> str: ... |
| 36 | +
|
| 37 | + # The last overload is a fallback in case the caller |
| 38 | + # provides a regular bool: |
| 39 | +
|
| 40 | + @overload |
| 41 | + def fetch_data(raw: bool) -> Union[bytes, str]: ... |
| 42 | +
|
| 43 | + def fetch_data(raw: bool) -> Union[bytes, str]: |
| 44 | + # Implementation is omitted |
| 45 | + ... |
| 46 | +
|
| 47 | + reveal_type(fetch_data(True)) # Revealed type is 'bytes' |
| 48 | + reveal_type(fetch_data(False)) # Revealed type is 'str' |
| 49 | +
|
| 50 | + # Variables declared without annotations will continue to have an |
| 51 | + # inferred type of 'bool'. |
| 52 | +
|
| 53 | + variable = True |
| 54 | + reveal_type(fetch_data(variable)) # Revealed type is 'Union[bytes, str]' |
| 55 | +
|
| 56 | +Parameterizing Literals |
| 57 | +*********************** |
| 58 | + |
| 59 | +Literal types may contain one or more literal bools, ints, strs, and bytes. |
| 60 | +However, literal types **cannot** contain arbitrary expressions: |
| 61 | +types like ``Literal[my_string.trim()]``, ``Literal[x > 3]``, or ``Literal[3j + 4]`` |
| 62 | +are all illegal. |
| 63 | + |
| 64 | +Literals containing two or more values are equivalent to the union of those values. |
| 65 | +So, ``Literal[-3, b"foo", True]`` is equivalent to |
| 66 | +``Union[Literal[-3], Literal[b"foo"], Literal[True]]``. This makes writing |
| 67 | +more complex types involving literals a little more convenient. |
| 68 | + |
| 69 | +Literal types may also contain ``None``. Mypy will treat ``Literal[None]`` as being |
| 70 | +equivalent to just ``None``. This means that ``Literal[4, None]``, |
| 71 | +``Union[Literal[4], None]``, and ``Optional[Literal[4]]`` are all equivalent. |
| 72 | + |
| 73 | +Literals may also contain aliases to other literal types. For example, the |
| 74 | +following program is legal: |
| 75 | + |
| 76 | +.. code-block:: python |
| 77 | +
|
| 78 | + PrimaryColors = Literal["red", "blue", "yellow"] |
| 79 | + SecondaryColors = Literal["purple", "green", "orange"] |
| 80 | + AllowedColors = Literal[PrimaryColors, SecondaryColors] |
| 81 | +
|
| 82 | + def paint(color: AllowedColors) -> None: ... |
| 83 | +
|
| 84 | + paint("red") # Type checks! |
| 85 | + paint("turquoise") # Does not type check |
| 86 | +
|
| 87 | +Literals may not contain any other kind of type or expression. This means doing |
| 88 | +``Literal[my_instance]``, ``Literal[Any]``, ``Literal[3.14]``, or |
| 89 | +``Literal[{"foo": 2, "bar": 5}]`` are all illegal. |
| 90 | + |
| 91 | +Future versions of mypy may relax some of these restrictions. For example, we |
| 92 | +plan on adding support for using enum values inside ``Literal[...]`` in an upcoming release. |
| 93 | + |
| 94 | +Declaring literal variables |
| 95 | +*************************** |
| 96 | + |
| 97 | +You must explicitly add an annotation to a variable to declare that it has |
| 98 | +a literal type: |
| 99 | + |
| 100 | +.. code-block:: python |
| 101 | +
|
| 102 | + a: Literal[19] = 19 |
| 103 | + reveal_type(a) # Revealed type is 'Literal[19]' |
| 104 | +
|
| 105 | +In order to preserve backwards-compatibility, variables without this annotation |
| 106 | +are **not** assumed to be literals: |
| 107 | + |
| 108 | +.. code-block:: python |
| 109 | +
|
| 110 | + b = 19 |
| 111 | + reveal_type(b) # Revealed type is 'int' |
| 112 | +
|
| 113 | +If you find repeating the value of the variable in the type hint to be tedious, |
| 114 | +you can instead change the variable to be :ref:`Final <final_attrs>`: |
| 115 | + |
| 116 | +.. code-block:: python |
| 117 | +
|
| 118 | + from typing_extensions import Final, Literal |
| 119 | +
|
| 120 | + def expects_literal(x: Literal[19]) -> None: pass |
| 121 | +
|
| 122 | + c: Final = 19 |
| 123 | +
|
| 124 | + reveal_type(c) # Revealed type is 'int' |
| 125 | + expects_literal(c) # ...but this type checks! |
| 126 | +
|
| 127 | +If you do not provide an explicit type in the Final, the type of ``c`` becomes |
| 128 | +context-sensitive: mypy will basically try "substituting" the original assigned |
| 129 | +value whenever it's used before performing type checking. So, mypy will type-check |
| 130 | +the above program almost as if it were written like so: |
| 131 | + |
| 132 | +.. code-block:: python |
| 133 | +
|
| 134 | + from typing_extensions import Final, Literal |
| 135 | +
|
| 136 | + def expects_literal(x: Literal[19]) -> None: pass |
| 137 | +
|
| 138 | + reveal_type(19) |
| 139 | + expects_literal(19) |
| 140 | +
|
| 141 | +This is why ``expects_literal(19)`` type-checks despite the fact that ``reveal_type(c)`` |
| 142 | +reports ``int``. |
| 143 | + |
| 144 | +So while changing a variable to be Final is not quite the same thing as adding |
| 145 | +an explicit ``Literal[...]`` annotation, it often leads to the same effect in practice. |
| 146 | + |
| 147 | +Limitations |
| 148 | +*********** |
| 149 | + |
| 150 | +Mypy will not understand expressions that use variables of type ``Literal[..]`` |
| 151 | +on a deep level. For example, if you have a variable ``a`` of type ``Literal[3]`` |
| 152 | +and another variable ``b`` of type ``Literal[5]``, mypy will infer that |
| 153 | +``a + b`` has type ``int``, **not** type ``Literal[8]``. |
| 154 | + |
| 155 | +The basic rule is that literal types are treated as just regular subtypes of |
| 156 | +whatever type the parameter has. For example, ``Literal[3]`` is treated as a |
| 157 | +subtype of ``int`` and so will inherit all of ``int``'s methods directly. This |
| 158 | +means that ``Literal[3].__add__`` accepts the same arguments and has the same |
| 159 | +return type as ``int.__add__``. |
0 commit comments