[Python-ideas] Fix documentation for __instancecheck__
Joy Diamond
python.gem at gmail.com
Sat Oct 27 22:21:04 EDT 2018
On Sat, Oct 27, 2018 at 10:00 PM Chris Angelico <rosuav at gmail.com> wrote:
> On Sun, Oct 28, 2018 at 12:53 PM Joy Diamond <python.gem at gmail.com> wrote:
> >> - 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?
> >
> >
> > 1. `type(x)` gets the true actual type of `x`.
> > 2. `x.__class__` gets the `.__class__` attribute for `x`, which by
> default gets the actual true type of `x`, but may be replace by the user to
> do other stuff.
> >
>
> Not that simple.
>
> >>> class X:
> ... cls = "X"
> ...
> >>> class Y:
> ... cls = "Y"
> ...
> >>> x = X()
> >>> x.__class__ = Y
> >>> x.cls
> 'Y'
> >>> type(x)
> <class '__main__.Y'>
>
> I don't know what the "true actual type" is, since I just changed it.
> In this case, type() and __class__ do exactly the same thing. The only
> way I know of (in Py3) to have them show different values is to make
> __class__ a property, and if you do that, I have no idea what uses the
> property and what uses type().
>
> Maybe this needs to be actually documented somewhere. It keeps on
> being a point of confusion.
>
> ChrisA
>
Yes, in your example, you actually changed the true actual type of `x` from
an `X` to a `Y`.
This is permitted since `X` and `Y` are "compatible". For example, if
instead you did [making `X` and `Y` no longer compatible]:
class X(object): __slots__ = (('x',))
class Y(object): __slots__ = (('y', 'z'))
x = X()
x.__class__ = Y
You get the following:
TypeError: __class__ assignment: 'X' object layout differs from 'Y'
Thus assigning to `.__class__` (when it has not been replaced by the user),
actually transforms an instance to a new true type.
[This is actually really useful in some rare edge cases, which is why
Python supports it].
Correct, you can make `__class__` a property to replace it (or play some
really difficult games with metaclasses to support a different `__class__`).
And, yes it is a point of confusion:
1. As per my earlier email, its best to use `.__class__`, as this is the
new way of doing things.
2. `type(x)` was the old [Python 1] way of doing things, looks incorrectly
like a constructor.
3. It would take weeks to fully document it; and there are many subtle
bugs probably in the python source code as to when it uses `.__class__` and
when it uses the true type -- i.e.: bypasses it all by using PY_Type(x).
CLARIFICATION: By "True actual type" -- I mean it's actual type as
implemented in the C code, and returns by the C [macro] `Py_Type(x)`.
That is, as defined at
https://github.com/python/cpython/blob/master/Include/object.h#L121
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
There are hundreds (704 in Python 2.7.12 for example) references to
`Py_TYPE` in the C code; thus it would take weeks to document it all.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20181027/25afea4c/attachment.html>
More information about the Python-ideas
mailing list