-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type narrowing with if None not in Sequence[Any | None]
not working as expected
#15001
Comments
Generally |
Yep seems like a duplicate. The cleanest way I've found to overcome this issue without changing the condition is with something like that. def test(a: int|None, b: int|None) -> int:
if None not in [a, b]:
a = cast(int, a)
b = cast(int, b)
reveal_type(a)
reveal_type(b)
return a+b
elif b is None:
return a
elif a is None:
return b
else:
return 0 However, I'm not sure if this would be considered good practice. Would love to get a feedback before closing this issue. Also, I did not quite understood why the following code in #10977 was unsafe because of invariance. Would love to get some explainations on it if possible :). There is no generic type involved so I don't get the issue here. a: set[Optional[str]]
if None in a:
return
reveal_type(a) |
For example: a: set[Optional[str]]
b = a
if None in a:
return
reveal_type(a) # set[str]
b.add(None)
reveal_type(a) # set[str] — but now it's a lie |
When a type checker applies type narrowing, it transforms a wider type to a narrower type. By definition, the narrower type must be a subtype of the wider type. Since |
It might be feasible to support type narrowing for both expressions I recommend avoiding this coding pattern and using something like this instead. It's behaviorally the same, slightly more performant at runtime, and type checks without a problem. def test(a: int | None, b: int | None) -> int:
if a is None:
if b is None:
return 0
return b
if b is None:
return a
return a + b |
Thanks @ikonst and @erictraut for your explanations! As has been previously stated, this seems like a duplicate of #10977, and I think all questions have been answered here, so I'm closing this now. |
Yep thanks for all the explaination ! Very instructive |
Bug Report
I expected that I could easily narrow multiple variables at once by using
None not in Sequence[Any | None]
. However mypy does not infer that. Nevertheless, after this condition it's impossible that variables have type None.To Reproduce
https://mypy-play.net/?mypy=latest&python=3.11&gist=40a2a733aa93c342e4ce013382949229
Expected Behavior
main.py:3: note: Revealed type is "builtins.int"
main.py:4: note: Revealed type is "builtins.int"
Actual Behavior
main.py:3: note: Revealed type is "Union[builtins.int, None]"
main.py:4: note: Revealed type is "Union[builtins.int, None]"
main.py:5: error: Unsupported operand types for + ("int" and "None") [operator]
main.py:5: error: Unsupported operand types for + ("None" and "int") [operator]
main.py:5: error: Unsupported left operand type for + ("None") [operator]
main.py:5: note: Both left and right operands are unions
main.py:7: error: Incompatible return value type (got "Optional[int]", expected "int") [return-value]
mypy.ini
(and other config files): NoneThe text was updated successfully, but these errors were encountered: