Any Narrowing Question #2444
-
Hi, while looking into a really complicated printing function in the rich codebase I finally narrowed down some pyright errors as originating from this behavior; the subsequent branches are getting narrowed to being We've discussed it for quite a while now in #python irc, but I think we need some clarification. from dataclasses import is_dataclass
from typing import Any
def analyze(obj: Any):
if is_dataclass(obj) and not isinstance(obj, type):
reveal_type(obj) # revealed as Any
else:
reveal_type(obj) # revealed as Any | type
def analyze_false(obj: Any):
if is_dataclass(obj) and not isinstance(obj, type) and False:
reveal_type(obj)
else:
reveal_type(obj) # revealed as Any | type Is this sort of narrowing to Any | type really needed? I can understand narrowing to unions with Any in general, but I don't understand why it should be considered appropriate here in the case of an and-buried isinstance check. Can you provide any examples of why the behavior is like this? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
This type evaluation result is a natural application of the normal rules for "or" and "and" expressions and In general, Consider this example. def analyze(obj: Any):
if isinstance(obj, int) or isinstance(obj, str):
reveal_type(obj) I think you'd agree that the revealed type should be Now, let's replace the first def analyze(obj: Any):
if random_function(obj) or isinstance(obj, str):
reveal_type(obj) Does it make sense that the revealed type would be Now, turning our attention back to your example. The type of def analyze(obj: Any):
if not is_dataclass(obj) or isinstance(obj, type):
reveal_type(obj) # Any | type The You might think "isn't |
Beta Was this translation helpful? Give feedback.
This type evaluation result is a natural application of the normal rules for "or" and "and" expressions and
isinstance
type narrowing.In general,
Any
is never narrowed (or widened), but there are three important exceptions to this rule:isinstance
,issubclass
, and a user-defined type guard function. These three cases are allowed to narrowAny
.Consider this example.
I think you'd agree that the revealed type should be
int | str
in this case.Now, let's replace the first
isinstance
call with a call to some other random function that doesn't imply any type narrowing.