Document we're not tracking relationships between symbols#16018
Document we're not tracking relationships between symbols#16018hauntsaninja merged 3 commits intopython:masterfrom
Conversation
| - :py:func:`issubclass` like in :code:`issubclass(cls, MyClass)` will narrow ``cls`` to be ``Type[MyClass]`` | ||
| - :py:class:`type` like in :code:`type(obj) is int` will narrow ``obj`` to have ``int`` type | ||
| - :py:func:`callable` like in :code:`callable(obj)` will narrow object to callable type | ||
| - :code:`obj is not None` will narrow object to its :ref:`non-optional form <strict_optional>` |
There was a problem hiding this comment.
strangely we didn't mention this
| Limitations of narrowing | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
Hope this is the right place. I wanted it to have a heading, to make it easy to refer people, but it's also a bit strange that it comes as a topic in the same hierarchy and right before "is_subclass" and "callable".
There was a problem hiding this comment.
Let's make it a heading and move it to the bottom of the page.
hauntsaninja
left a comment
There was a problem hiding this comment.
Thanks for writing this up!
| Limitations of narrowing | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
Let's make it a heading and move it to the bottom of the page.
| return 'spam' | ||
|
|
||
| Tracking these sort of cross-variable conditions in a type checker would add significant complexity | ||
| and performance overhead and would be computationally infeasible in all but the most basic cases. |
There was a problem hiding this comment.
| and performance overhead and would be computationally infeasible in all but the most basic cases. | |
| and performance overhead. |
Claim feels a little too strong, first half of the sentence says enough.
| Tracking these sort of cross-variable conditions in a type checker would add significant complexity | ||
| and performance overhead and would be computationally infeasible in all but the most basic cases. | ||
|
|
||
| You may override the type checker with a :ref:`cast <casts>`, or rewrite the function to be |
There was a problem hiding this comment.
| You may override the type checker with a :ref:`cast <casts>`, or rewrite the function to be | |
| You may override the type checker with an ``assert`` or :ref:`cast <casts>`, or rewrite the function to be |
When I run into this, assert is usually more ergonomic. It's also safer than cast.
There was a problem hiding this comment.
Probably would phrase as "help the type checker with an assert", but I'm not sure it'll be more ergonomic in this case. Maybe I'm tired and missing something obvious?
cast:
def f(a: str | None, b: str | None) -> str:
if a is not None or b is not None:
return a or cast(str, b)
return 'spam'assert:
def f(a: str | None, b: str | None) -> str:
if a is not None or b is not None:
if a:
return a
assert b is not None
return b
return 'spam'third option:
def f(a: str | None, b: str | None) -> str:
if a is not None or b is not None:
return a or b or 'impossible'
return 'spam'There was a problem hiding this comment.
Yeah, not more ergonomic in this case, but better in the cases where I usually run into this. But maybe I dislike cast more than most people :-)
I'd do assert a or b; return a or b
There was a problem hiding this comment.
assert a or b doesn't help you either because we don't narrow conditionally. (Also, in this case you'd get more than you'd bargain for, as empty b would assert.)
There was a problem hiding this comment.
Oh oops, I guess you'd have to do ret = a or b; assert ret is not None; return ret
Fixes #15653.
I did not use @erictraut's "quantum entanglement" metaphor, though I find it to be quite illustrative :)