[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