This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author steven.daprano
Recipients Gabriele Tornetta, bup, ethan.furman, paul.moore, r.david.murray, rhettinger, steven.daprano
Date 2021-12-10.02:30:22
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <20211210022746.GV21647@ando.pearwood.info>
In-reply-to <1639066721.22.0.721643276169.issue32683@roundup.psfhosted.org>
Content
I agree that the rules regarding type and `__class__` and isinstance are 
not clear or well documented.

We have:

https://docs.python.org/3/library/stdtypes.html#instance.__class__

https://docs.python.org/3/library/functions.html#isinstance

but neither discuss the interaction between a class' "real" type and 
it's "fake" type.

To be honest, I'm not even sure I fully understand the interaction 
myself, or how they combine with virtual subclasses. A lot of my 
information comes from this Stackoverflow post:

https://stackoverflow.com/questions/1060499/difference-between-typeobj-and-obj-class

and in particular this comment:

"Some code does this deliberately to lie about the type of objects, such 
as weakref.proxy. Some people think obj.__class__ should be preferred, 
because it believes the lie, while some people think type(obj) should be 
preferred because it ignores the lie. isinstance will return true if an 
object's real class or its lie class is an instance of the second 
argument."

So I think that the behaviour here is correct, but it is not documented 
well and we should fix that.

What I think happens:

* type(obj) always and only returns the actual internal (C-level) type 
  of the object, guaranteed to be a type object.

* isinstance(obj, classinfo) returns True if any of the following hold:

  - the type() of object is a subclass of any of the classes in the
    classinfo object (a class, a Union of classes, or a tuple of 
    classes);

  - obj.__class__ is a subclass of any of the classes in classinfo;

  - or obj is registered as a virtual subclass of any of the classes
    in classinfo, by calling type(ob).__subclasshook__;

* obj.__class__ is determined using the normal attribute lookup 
  mechanism, which means it does not have to be a static attribute
  but can be dynamically generated using properties, __getattr__,
  __getattribute__ or any other similar mechanism.

And for the avoidance of doubt, a class is always considered a subclass 
of itself.

I'm really not sure about the interaction with virtual subclasses, I 
probably have that bit wrong. And it is not clear to me what happens if 
__class__ is a non-type object. It seems to be permitted.

Improving the documentation would be excellent.
History
Date User Action Args
2021-12-10 02:30:22steven.dapranosetrecipients: + steven.daprano, rhettinger, paul.moore, r.david.murray, ethan.furman, bup, Gabriele Tornetta
2021-12-10 02:30:22steven.dapranolinkissue32683 messages
2021-12-10 02:30:22steven.dapranocreate