Skip to content

is_member_of_type #2

@lucaswiman

Description

@lucaswiman

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions