-
Notifications
You must be signed in to change notification settings - Fork 38
Description
The most useful introspection methods I'd like to use from the typing
module are basically the functions that were removed in python/typing#283: checking whether a concrete object is compatible with a given type. This would be useful for simple runtime type assertions, for exploring the implications of PEP484 in the REPL, and annotations-based dispatch.
Please let me know what you think; I'd be very interested in helping to implement this. I can also submit a PR if that makes discussion easier.
Objections
Should this be in external tools?
@1st1 objected to this on the grounds that it should be left to external tools, but it seems like implementing a reference for cases which are unambiguous according to PEP484 would be quite useful, and even helpful to building external tools of that kind.
For cases where something other than recursive isinstance
calls are required (e.g. type variables), a helpful error can be raised at runtime.
Mutable values
There was an objection to __instancecheck__
and __subclasscheck__
by BDFL-delegate @markshannon here:
For example,
List[int] and List[str] and mutually incompatible types, yet
isinstance([], List[int]) and isinstance([], List[str))
both return true.
This is a bit tricky for mutable types, since []
is a member of List[X]
for all X
, but the same list object might cease to be in List[X]
when elements are added to it. For immutable types, the answer is unambiguous, so Tuple[*]
could always deliver an unambiguous answer.
For List[]
, Dict[]
and other mutable types, my preference would be to check the types of the elements right now, when the method is called, and not at some future time when it may have been mutated. This would be a distinction between mypy
and the runtime type checking, but this behavior seems more in keeping with the principle of least surprise, and would accord with the main intended use cases (REPL-based exploration of the type system, and simple runtime type assertions).
Implementation
I think the implementation would be roughly like the following:
def is_member_of_type(obj, tp):
if has_type_variables(tp):
raise ValueError('Type variables cannot be determined at runtime')
if is_union(tp):
return any(is_member_of_type(obj, s) for s in tp.__args__)
elif is_tuple(tp):
...
elif ...:
...
else:
return isinstance(obj, tp)
Include issubtype
to match issubclass
?
issubtype
could make sense as an addition, but it would involve introducing much more of the sorts of logic a typechecker should implement, e.g. the following:
>>> from typing import *
>>> class MyTuple(NamedTuple):
... foo: int
... bar: str
...
>>> issubtype(MyTuple, Tuple[int, str])
True
For this reason, I think it would make more sense to leave issubtype
out of typing_inspect
.