mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-02 21:03:11 +00:00
2.4 KiB
2.4 KiB
Narrowing in boolean expressions
In or expressions, the right-hand side is evaluated only if the left-hand side is falsy. So
when the right-hand side is evaluated, we know the left side has failed.
Similarly, in and expressions, the right-hand side is evaluated only if the left-hand side is
truthy. So when the right-hand side is evaluated, we know the left side has succeeded.
Narrowing in or
def _(flag: bool):
class A: ...
x: A | None = A() if flag else None
isinstance(x, A) or reveal_type(x) # revealed: None
x is None or reveal_type(x) # revealed: A
reveal_type(x) # revealed: A | None
Narrowing in and
from typing import final
def _(flag: bool):
class A: ...
x: A | None = A() if flag else None
isinstance(x, A) and reveal_type(x) # revealed: A
x is None and reveal_type(x) # revealed: None
reveal_type(x) # revealed: A | None
@final
class FinalClass: ...
# We know that no subclass of `FinalClass` can exist,
# therefore no subtype of `FinalClass` can define `__bool__`
# or `__len__`, therefore `FinalClass` can safely be considered
# always-truthy, therefore this always resolves to `None`
reveal_type(FinalClass() and None) # revealed: None
Multiple and arms
def _(flag1: bool, flag2: bool, flag3: bool, flag4: bool):
class A: ...
x: A | None = A() if flag1 else None
flag2 and isinstance(x, A) and reveal_type(x) # revealed: A
isinstance(x, A) and flag2 and reveal_type(x) # revealed: A
reveal_type(x) and isinstance(x, A) and flag3 # revealed: A | None
Multiple or arms
def _(flag1: bool, flag2: bool, flag3: bool, flag4: bool):
class A: ...
x: A | None = A() if flag1 else None
flag2 or isinstance(x, A) or reveal_type(x) # revealed: None
isinstance(x, A) or flag3 or reveal_type(x) # revealed: None
reveal_type(x) or isinstance(x, A) or flag4 # revealed: A | None
Multiple predicates
from typing import Literal
def _(flag1: bool, flag2: bool):
class A: ...
x: A | None | Literal[1] = A() if flag1 else None if flag2 else 1
x is None or isinstance(x, A) or reveal_type(x) # revealed: Literal[1]
Mix of and and or
from typing import Literal
def _(flag1: bool, flag2: bool):
class A: ...
x: A | None | Literal[1] = A() if flag1 else None if flag2 else 1
isinstance(x, A) or x is not None and reveal_type(x) # revealed: Literal[1]