Special typing construct for marking user-defined type predicate functions. ``TypeGuard`` can be used to annotate the return type of a user-defined type predicate function. ``TypeGuard`` only accepts a single type argument. At runtime, functions marked this way should return a boolean.
(self, parameters)
| 849 | |
| 850 | @_SpecialForm |
| 851 | def TypeGuard(self, parameters): |
| 852 | """Special typing construct for marking user-defined type predicate functions. |
| 853 | |
| 854 | ``TypeGuard`` can be used to annotate the return type of a user-defined |
| 855 | type predicate function. ``TypeGuard`` only accepts a single type argument. |
| 856 | At runtime, functions marked this way should return a boolean. |
| 857 | |
| 858 | ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static |
| 859 | type checkers to determine a more precise type of an expression within a |
| 860 | program's code flow. Usually type narrowing is done by analyzing |
| 861 | conditional code flow and applying the narrowing to a block of code. The |
| 862 | conditional expression here is sometimes referred to as a "type predicate". |
| 863 | |
| 864 | Sometimes it would be convenient to use a user-defined boolean function |
| 865 | as a type predicate. Such a function should use ``TypeGuard[...]`` or |
| 866 | ``TypeIs[...]`` as its return type to alert static type checkers to |
| 867 | this intention. ``TypeGuard`` should be used over ``TypeIs`` when narrowing |
| 868 | from an incompatible type (e.g., ``list[object]`` to ``list[int]``) or when |
| 869 | the function does not return ``True`` for all instances of the narrowed type. |
| 870 | |
| 871 | Using ``-> TypeGuard[NarrowedType]`` tells the static type checker that |
| 872 | for a given function: |
| 873 | |
| 874 | 1. The return value is a boolean. |
| 875 | 2. If the return value is ``True``, the type of its argument |
| 876 | is ``NarrowedType``. |
| 877 | |
| 878 | For example:: |
| 879 | |
| 880 | def is_str_list(val: list[object]) -> TypeGuard[list[str]]: |
| 881 | '''Determines whether all objects in the list are strings''' |
| 882 | return all(isinstance(x, str) for x in val) |
| 883 | |
| 884 | def func1(val: list[object]): |
| 885 | if is_str_list(val): |
| 886 | # Type of ``val`` is narrowed to ``list[str]``. |
| 887 | print(" ".join(val)) |
| 888 | else: |
| 889 | # Type of ``val`` remains as ``list[object]``. |
| 890 | print("Not a list of strings!") |
| 891 | |
| 892 | Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower |
| 893 | form of ``TypeA`` (it can even be a wider form) and this may lead to |
| 894 | type-unsafe results. The main reason is to allow for things like |
| 895 | narrowing ``list[object]`` to ``list[str]`` even though the latter is not |
| 896 | a subtype of the former, since ``list`` is invariant. The responsibility of |
| 897 | writing type-safe type predicates is left to the user. |
| 898 | |
| 899 | ``TypeGuard`` also works with type variables. For more information, see |
| 900 | PEP 647 (User-Defined Type Guards). |
| 901 | """ |
| 902 | item = _type_check(parameters, f'{self} accepts only single type.') |
| 903 | return _GenericAlias(self, (item,)) |
| 904 | |
| 905 | |
| 906 | @_TypeFormForm |
searching dependent graphs…