__instancecheck__ and __subclasscheck__ on non-types

I’m intending to build a data structure which contains many thousands of “types”.

Experimenting with timeit and sys.getsizeof suggests that instances of type are at least ten times the size of an instance of some simple type, and take a hundred times as long to construct. So I’d very much prefer to be creating something more lightweight.

By experimentation, I have discovered that - in CPython, at least - this works:

class FakeType:
    def __instancecheck__(self, inst):
        return True
    def __subclasscheck__(self, cls):
        return True

fake = FakeType()
assert( issubclass('not even a type', fake) )

But reading the docs, I see:

isinstance(object, classinfo )

Return True if the object argument is an instance of the classinfo argument, or of a (direct, indirect, or virtual) subclass thereof. If object is not an object of the given type, the function always returns False. If classinfo is a tuple of type objects (or recursively, other such tuples) or a Union Type of multiple types, return True if object is an instance of any of the types. If classinfo is not a type or tuple of types and such tuples, a TypeError exception is raised. TypeError may not be raised for an invalid type if an earlier check succeeds.

So… while this feels like a reasonable thing to do, and common sense that it should work, the only documentation I can find implies it doesn’t. Does this mean it might break in future versions, I’m not entitled to have it work in other Python implementations, etc.?

1 Like

My guess is that this behavior, although undocumented, is here to stay because it allows a typing._SpecialForm instance (such as typing.Never, typing.Self, etc.), which behaves like a type when used in typing context, to produce a more helpful error message when an attempt to use it as a type outside of a typing context is made:

1 Like