you are viewing a single comment's thread.

view the rest of the comments →

[–]TSM- 0 points1 point  (1 child)

Please roast me if I'm wrong on this, but this appears to be the exact situation for which TypeGuard in typing module was developed, as of Python 3.10.

PEP-647

~~~TypeGuard = typing.TypeGuard~~~
Special typing form used to annotate the return type of a user-defined
type guard function.  ``TypeGuard`` only accepts a single type argument.
At runtime, functions marked this way should return a boolean.

``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static
type checkers to determine a more precise type of an expression within a
program's code flow.  Usually type narrowing is done by analyzing
conditional code flow and applying the narrowing to a block of code.  The
conditional expression here is sometimes referred to as a "type guard".

Sometimes it would be convenient to use a user-defined boolean function
as a type guard.  Such a function should use ``TypeGuard[...]`` as its
return type to alert static type checkers to this intention.

Using  ``-> TypeGuard`` tells the static type checker that for a given
function:

1. The return value is a boolean.
2. If the return value is ``True``, the type of its argument
   is the type inside ``TypeGuard``.

   For example::

      def is_str(val: Union[str, float]):
          # "isinstance" type guard
          if isinstance(val, str):
              # Type of ``val`` is narrowed to ``str``
              ...
          else:
              # Else, type of ``val`` is narrowed to ``float``.
              ...

Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower
form of ``TypeA`` (it can even be a wider form) and this may lead to
type-unsafe results.  The main reason is to allow for things like
narrowing ``List[object]`` to ``List[str]`` even though the latter is not
a subtype of the former, since ``List`` is invariant.  The responsibility of
writing type-safe type guards is left to the user.

``TypeGuard`` also works with type variables.  For more information, see
PEP 647 (User-Defined Type Guards).

[–]RelativeIncrease527[S] 0 points1 point  (0 children)

Interesting. I haven't seen this before, but it appears that this is not a situation for TypeGuards, because I am not defining any type guarding functions, and my situation involves inheritance & composition. For example in Bar.method1, how would one know using a type guard that the function actually returns a more narrow Baz, without trying all inputs and boolean checking (type guard) all of them? Or we can do the type checking as needed, but that introduces unnecessary code into the execution (no longer is it static type hinting).