[Python-ideas] Fix documentation for __instancecheck__

Terry Reedy tjreedy at udel.edu
Sat Oct 27 16:09:03 EDT 2018


On 10/27/2018 2:53 PM, Joy Diamond wrote:
> Chris,
> 
> Yes, the following works:
> """
> (Note that any object `x` is always considered to be an instance of
> `type(x)`, and this cannot be overridden.)
> """

Open a doc issue on bugs.python.org with the problem, motivation, and 
proposed solution and it should get considered.

> NOTE:  I fixed your sentence of `x.__class__` to `type(x)` since it is 
> not always true that `x.__class__ == type(x)`.
> 
> For example the actual code reference above:
> 
> https://github.com/python/cpython/blob/master/Objects/abstract.c#L2397-L2405
> 
> Says "if (Py_TYPE(inst) == (PyTypeObject *)cls)" in the actual C Python 
> implementation:
> 
> So it using `type(x)` not `x.__class__`
> 
> Thanks,
> 
> Joy Diamond.
> 
> ====
> 
> ADDENDUM:
> 
> Here is an example where `type(x) is not x.__class__`   (there are other 
> not as perverse examples where you want `.__class__` to differ from `type`)
> 
> NOTE:  The final assert will fail, showing that `type(x) is not x.__class__`
> 
> #
> #   This really perverse code demonstrates that `t.__class__` is *NOT*
> #   always the same as type(t).
> #
> #  The code shows an metaclass that when you derive objects from its 
> classes, creates a `7`
> #  instead of a derived class.
> #
> def not_really_a_metaclass__make_a_7(name, bases, member):
>      return 7
> 
> @property
> def not_really_a_class__make_a_7(t):
>      return not_really_a_metaclass__make_a_7
> 
> class Metaclass__Make_A_7(type):
>      __class__ = not_really_a_class__make_a_7
> 
> Make_A_7 = Metaclass__Make_A_7('Make_A_7', ((object,)), {})
> 
> 
> #
> #   Now then:
> #
> #       `Make_A_7` is a class that when inherited from creates a '7' instead
> #       of a class ... :(
> #
> #   Works for python 2 & pypy (not yet fixed to work for python 3)
> #
> class Seven(Make_A_7):  # Calls `Make_A_7.__class__('Seven, 
> (('Make_A_7,)), {})` which returns `7`
>      pass
> 
> print('Seven is: %s' % Seven)
> 
> assert isinstance(Make_A_7, Metaclass__Make_A_7)
> assert Make_A_7.__class__ == Metaclass__Make_A_7   #  This will *FAIL* 
> due to the perverse definition of `.__class__`
> 
> On Sat, Oct 27, 2018 at 2:25 PM Chris Angelico 
> <rosuav at gmail.com 
> <mailto:rosuav at gmail.com>> wrote:
> 
>     On Sun, Oct 28, 2018 at 5:03 AM Joy Diamond
>     <python.gem at gmail.com
>     <mailto:python.gem at gmail.com>> wrote:
>      >
>      > Greetings,
>      >
>      > This is a request to fix the documentation for __instancecheck__.
>      >
>      > Please add the following (please rewrite better than I can -- I
>     am not good at explaining concepts in short sentences):
>      >
>      > NOTE:  As an optimization, isinstance(object, classinfo) does NOT
>     call classinfo.__instancecheck__(instance) when type(object) ==
>     classinfo.
>      >
>      > Consider the following program:
>      >
>      > class M(type):
>      >     def __instancecheck__(m, t):
>      >         print('instancecheck(%s, %s)' % (m, t))
>      >         return False                                    #   LIE!
>      >
>      > Test = M('Test', ((object,)), {})
>      >
>      > something = Test()
>      >
>      > print('Does *NOT* call __instancecheck__:')
>      > print('isinstance(something, Test): %s' % isinstance(something,
>     Test))
> 
>     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. The implication of "override" is that you can completely
>     replace the normal behaviour. 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. 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.)
>     """
> 
>     Would that work?
> 
>     ChrisA
>     _______________________________________________
>     Python-ideas mailing list
>     Python-ideas at python.org
>     <mailto:Python-ideas at python.org>
>     https://mail.python.org/mailman/listinfo/python-ideas
>     Code of Conduct: http://python.org/psf/codeofconduct/
> 
> 
> 
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
> 


-- 
Terry Jan Reedy




More information about the Python-ideas mailing list