@@ -1151,148 +1151,3 @@ section of the docs has a full description with an example, but in short, you wi
1151
1151
need to give each TypedDict the same key where each value has a unique
1152
1152
unique :ref: `Literal type <literal_types >`. Then, check that key to distinguish
1153
1153
between your TypedDicts.
1154
-
1155
-
1156
- User-Defined Type Guards
1157
- ************************
1158
-
1159
- Mypy supports User-Defined Type Guards
1160
- (:pep: `647 `).
1161
-
1162
- A type guard is a way for programs to influence conditional
1163
- type narrowing employed by a type checker based on runtime checks.
1164
-
1165
- Basically, a ``TypeGuard `` is a "smart" alias for a ``bool `` type.
1166
- Let's have a look at the regular ``bool `` example:
1167
-
1168
- .. code-block :: python
1169
-
1170
- from typing import List
1171
-
1172
- def is_str_list (val : List[object ]) -> bool :
1173
- """ Determines whether all objects in the list are strings"""
1174
- return all (isinstance (x, str ) for x in val)
1175
-
1176
- def func1 (val : List[object ]) -> None :
1177
- if is_str_list(val):
1178
- reveal_type(val) # Reveals List[object]
1179
- print (" " .join(val)) # Error: incompatible type
1180
-
1181
- The same example with ``TypeGuard ``:
1182
-
1183
- .. code-block :: python
1184
-
1185
- from typing import List
1186
- from typing import TypeGuard # use `typing_extensions` for Python 3.9 and below
1187
-
1188
- def is_str_list (val : List[object ]) -> TypeGuard[List[str ]]:
1189
- """ Determines whether all objects in the list are strings"""
1190
- return all (isinstance (x, str ) for x in val)
1191
-
1192
- def func1 (val : List[object ]) -> None :
1193
- if is_str_list(val):
1194
- reveal_type(val) # List[str]
1195
- print (" " .join(val)) # ok
1196
-
1197
- How does it work? ``TypeGuard `` narrows the first function argument (``val ``)
1198
- to the type specified as the first type parameter (``List[str] ``).
1199
-
1200
- .. note ::
1201
-
1202
- Narrowing is
1203
- `not strict <https://www.python.org/dev/peps/pep-0647/#enforcing-strict-narrowing >`_.
1204
- For example, you can narrow ``str `` to ``int ``:
1205
-
1206
- .. code-block :: python
1207
-
1208
- def f (value : str ) -> TypeGuard[int ]:
1209
- return True
1210
-
1211
- Note: since strict narrowing is not enforced, it's easy
1212
- to break type safety.
1213
-
1214
- However, there are many ways a determined or uninformed developer can
1215
- subvert type safety -- most commonly by using cast or Any.
1216
- If a Python developer takes the time to learn about and implement
1217
- user-defined type guards within their code,
1218
- it is safe to assume that they are interested in type safety
1219
- and will not write their type guard functions in a way
1220
- that will undermine type safety or produce nonsensical results.
1221
-
1222
- Generic TypeGuards
1223
- ------------------
1224
-
1225
- ``TypeGuard `` can also work with generic types:
1226
-
1227
- .. code-block :: python
1228
-
1229
- from typing import Tuple, TypeVar
1230
- from typing import TypeGuard # use `typing_extensions` for `python<3.10`
1231
-
1232
- _T = TypeVar(" _T" )
1233
-
1234
- def is_two_element_tuple (val : Tuple[_T, ... ]) -> TypeGuard[Tuple[_T, _T]]:
1235
- return len (val) == 2
1236
-
1237
- def func (names : Tuple[str , ... ]):
1238
- if is_two_element_tuple(names):
1239
- reveal_type(names) # Tuple[str, str]
1240
- else :
1241
- reveal_type(names) # Tuple[str, ...]
1242
-
1243
- Typeguards with parameters
1244
- --------------------------
1245
-
1246
- Type guard functions can accept extra arguments:
1247
-
1248
- .. code-block :: python
1249
-
1250
- from typing import Type, Set, TypeVar
1251
- from typing import TypeGuard # use `typing_extensions` for `python<3.10`
1252
-
1253
- _T = TypeVar(" _T" )
1254
-
1255
- def is_set_of (val : Set[Any], type : Type[_T]) -> TypeGuard[Set[_T]]:
1256
- return all (isinstance (x, type ) for x in val)
1257
-
1258
- items: Set[Any]
1259
- if is_set_of(items, str ):
1260
- reveal_type(items) # Set[str]
1261
-
1262
- TypeGuards as methods
1263
- ---------------------
1264
-
1265
- A method can also serve as the ``TypeGuard ``:
1266
-
1267
- .. code-block :: python
1268
-
1269
- class StrValidator :
1270
- def is_valid (self , instance : object ) -> TypeGuard[str ]:
1271
- return isinstance (instance, str )
1272
-
1273
- def func (to_validate : object ) -> None :
1274
- if StrValidator().is_valid(to_validate):
1275
- reveal_type(to_validate) # Revealed type is "builtins.str"
1276
-
1277
- .. note ::
1278
-
1279
- Note, that ``TypeGuard ``
1280
- `does not narrow <https://www.python.org/dev/peps/pep-0647/#narrowing-of-implicit-self-and-cls-parameters >`_
1281
- types of ``self `` or ``cls `` implicit arguments.
1282
-
1283
- If narrowing of ``self `` or ``cls `` is required,
1284
- the value can be passed as an explicit argument to a type guard function:
1285
-
1286
- .. code-block :: python
1287
-
1288
- class Parent :
1289
- def method (self ) -> None :
1290
- reveal_type(self ) # Revealed type is "Parent"
1291
- if is_child(self ):
1292
- reveal_type(self ) # Revealed type is "Child"
1293
-
1294
- class Child (Parent ):
1295
- ...
1296
-
1297
- def is_child (instance : Parent) -> TypeGuard[Child]:
1298
- return isinstance (instance, Child)
0 commit comments