[Python-ideas] Fix documentation for __instancecheck__
Steven D'Aprano
steve at pearwood.info
Sat Oct 27 20:01:46 EDT 2018
On Sun, Oct 28, 2018 at 05:24:43AM +1100, Chris Angelico wrote:
> On Sun, Oct 28, 2018 at 5:03 AM Joy Diamond <python.gem at gmail.com> wrote:
> > NOTE: As an optimization, isinstance(object, classinfo) does NOT
> > call classinfo.__instancecheck__(instance) when type(object) ==
> > classinfo.
I'd like to discuss this optimization. It seems very strange to me that
a method designed specifically to override the isinstance check isn't
actually called to allow it to override the isinstance check.
[Chris]
> Here's the passage in question, for reference:
>
> """
> The following methods are used to override the default behavior of the
> isinstance() and issubclass() built-in functions.
>
> In particular, the metaclass abc.ABCMeta implements these methods in
> order to allow the addition of Abstract Base Classes (ABCs) as
> “virtual base classes” to any class or type (including built-in
> types), including other ABCs.
> """
> https://docs.python.org/3/reference/datamodel.html#customizing-instance-and-subclass-checks
>
> Since it uses the word "override", I agree that it's not entirely
> correct.
Is that a polite way of saying "wrong"?
The question we should be asking, is the optimization implementing the
desired behaviour:
* classes can disown instances of subclasses
* but they cannot disown their own instances
or is the optimization over-zealous and does too much?
I don't think it is obvious that the behaviour is correct. Presumably
Joy had a use-case for overriding isinstance(), and this optimization
prevented it.
Joy, can you comment on your use-case, and did you come up with a
work-around?
> The implication of "override" is that you can completely
> replace the normal behaviour.
Indeed.
> In this case, you can change the
> behaviour of subclass testing (for instance, you can "disown" a
> subclass by denying that instances of it are instances of yourself),
> and of course, you can claim an object as an instance of a class it
> didn't directly inherit from (the way ABCs work), but you cannot fib
> about direct instances.
But we can change the class of direct instances, by changing their
__class__ attribute, and that is intentional, supported behaviour. So
"fibbing" is allowed.
Perhaps changing the __class__ is enough to work-around this
optimization, and there's nothing to do here except to document it
better. But I think that if it is useful to own a non-instance, we
shouldn't be so blasé about prohibiting disowning an instance.
> I think the behaviour is close enough to
> accurate that it doesn't need major rewording; how about adding this
> parenthesis:
>
> """
> (Note that any object `x` is always considered to be an instance of
> `x.__class__`, and this cannot be overridden.)
> """
I would rather be precise about what is going on, and state that
X.__instancecheck__(x) is not called if type(x) is X, rather than merely
imply it. It is not just that the method is called and ignored, but
that it isn't called at all.
I find the process of checking types rather opaque and mysterious. Do we
have a documented (other than the source) algorithm for deciding what is
an instance of what?
- type(x) and x.__class__ don't necessarily agree; under what
circumstances are each used?
(I've asked this before, and either never got a good answer, or I can't
keep it straight in my head.)
- what precisely does type(x) do?
- when is __instancecheck__ called?
A flowchart would be good :-)
--
Steve
More information about the Python-ideas
mailing list