cpython
cpython copied to clipboard
Passage on TypeVar isinstance/issubclass is unclear
Documentation
This passage is problematic:
At runtime, isinstance(x, T) will raise TypeError. In general, isinstance() and issubclass() should not be used with types.
- It says "in general", but there are no known exceptions.
- It says "should not be used with types", whereas it should say "used with type variables".
Re your point 1: what about unknown exceptions? The point of saying "in general, don't do this" is that it allows for the hypothetical existence of exceptions, without requiring that the doc author conclusive prove the existence of at least one exception.
(In this case, the obvious exceptions include concrete types (classes) such as int
, as well as special types such as Union
.)
The documentation here is giving some general advice not making a hard and fast rule. This is a standard English idiom; out of the ten examples given by TFD four of them do not give any exceptions.
Re your point 2, your correction is ambiguous. The exact wording of point two suggests that you want to replace
In general,
isinstance()
andissubclass()
should not be used with types.
with
In general,
isinstance()
andissubclass()
used with type variables.
but that is grammatically invalid, so I presume you probably mean to just substitute "type variables" for "types". Am I correct?
In general,
isinstance()
andissubclass()
should not be used with type variables.
But that would be wrong. That's not a general rule, that is a particular rule, and there are no exceptions: you can never use TypeVars with isinstance.
The advice here doesn't just apply to type variables such as TypeVar['T']
, but to any static type such as Any
, ParamSpec('P')
, NoReturn
, parameterized generics such as list[int]
, None (used as a short-hand for NoneType) etc.
So I think that the documentation is correct, not problematic or wrong, although perhaps we could clarify it by making it more clear:
- outside of the context of static typing, "type" and "class" are synonyms;
- in the context of static typing. "type" can include objects which are not classes;
- consequently, not all (static typing) types are usable with
isinstance
andissubclass
.
Thinking some more about this, it seems like the documentation doesn't do a great job of making it clear which (static) types are usable with isinstance
and which are not. The reader doesn't learn the general rule unless they dive deep into TypeVar
, so it is easy to miss.
I suggest that the docs have an early section clarifying the distinction between "type" as a synonym for "class" at runtime, and "type" in the static typing sense, state the rule that unless otherwise documented we should assume than static types cannot be used with isinstance
and issubclass
, and then document the exceptions.
It might also be nice to have a recipe for how to tell at runtime whether some arbitrary object is usable with isinstance
and issubclass
. I think that isinstance(obj, type)
will do it, but I'm not sure if there are exceptions.
The following is semantically correct: "in general you shouldn't add integers to strings". The (hopefully obvious) reality is: you can't add integers to strings. There are no specific instances where type variables can be used as the class_or_tuple
argument of isinstance
and issubclass
. This is a minor point though so if your objection stands, I won't press it further.
I do agree with your points about this applying to other types. This passage is in the "class typing.TypeVar" section of the document. So, I agree a passage should be moved to a earlier section, not specific to any particular type. To that end, I'll cancel PR #98309 I submitted to correct this passage.
I agree with you that the particular case of TypeVar can never be used with isinstance -- if there is an exception it is beyond my ability to find. However the docs are referring to the general case of (static) types not being usable with isinstance, so I agree with you that this should be moved out of the specific case of TypeVar and into a general section.
ClassVar also explicitly describes itself as not being usable with isinstance. If we change to documenting this as "default deny" (types are not usable with isinstance unless documented otherwise) then that clause will become redundant and may be removed.
Are you able to submit a revised PR for this? Thanks in advance.
Would you suggest at the top of Building generic types?
I agree that our current wording is not the best.
At runtime, isinstance(x, T) will raise TypeError. In general, isinstance() and issubclass() should not be used with types.
isinstance
should be used with types! Like str
, int
, or custom ones.
But, it should not be used with "typing objects". Like TypeVar
, Literal
, Generic
, etc.
We recently just deleted this sentence from the docs; it was indeed confusing. Closing this as completed!