Variable doesn't type narrow on reassignment to itself? #10781
-
In the following code, I expect from typing import TextIO, reveal_type
import sys
reveal_type(sys.stdout) # it says TextIO | Any (it's a MaybeNone from typeshed)
def g(stdout: TextIO):
pass
def f(stdout: TextIO | None = None):
stdout = stdout if stdout is not None else sys.stdout
g(stdout) # it says stdout is TextIO | None so it can't be assigned.
def example_function_which_is_fine():
g(sys.stdout) Code sample in pyright playground |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
The behavior you're seeing here is due to the |
Beta Was this translation helpful? Give feedback.
-
That's surprising to me. I thought it would be narrowed to Oh, I guess this makes it clearer to me (hovertext from pyright playground included as comments): def f2(stdout: TextIO | None = None):
if stdout is not None:
stdout = stdout # (parameter) stdout: TextIO = (parameter) stdout: TextIO
else:
stdout = sys.stdout # (parameter) stdout: TextIO | None = (variable) stdout: TextIO | Any
g(stdout) # it says stdout is TextIO | None so it can't be assigned. When it considers assigning sys.stdout to stdout, it says "yeah, that Any could be a None. I will keep the original type", and thus doesn't change it. Presumably, the ternary is doing this as well. The same is true also for this even simpler case: def f3(stdout: TextIO | None = None):
stdout = sys.stdout
g(stdout) # it says stdout is TextIO | None so it can't be assigned. |
Beta Was this translation helpful? Give feedback.
The behavior you're seeing here is due to the
Any
type in thesys.stdout
type definition. Since thatAny
could be aNone
, it's unsafe to narrow the type ofstdout
to justTextIO
. So this is intended behavior, not a bug.