2

Why is this printing a False?

#! /usr/bin/env python

class A(object):
    def __instancecheck__(self,arg):
        print self, type(self), arg , type(arg)

if __name__ == '__main__':
    a = A()
    print isinstance(a,a)

Gives:

$ ./isinstancecheck.py 
<__main__.A object at 0x7f0574198b90> <class '__main__.A'> <__main__.A object at     0x7f0574198b90> <class '__main__.A'>
False
Kabie
  • 10,489
  • 1
  • 38
  • 45
Ankur Agarwal
  • 23,692
  • 41
  • 137
  • 208
  • Due to the Python specification, overriding `__instancecheck__` does not seem to work in some cases: https://stackoverflow.com/questions/52168971/instancecheck-overwrite-shows-no-effect-what-am-i-doing-wrong – mikm May 18 '23 at 10:35

2 Answers2

3

According to the documentation, __instancecheck__ should return True or False.

But, A.__instancecheck__ in your code does return Nothing; None is returned implicitly; None is treated as False; so the False is printed.

falsetru
  • 357,413
  • 63
  • 732
  • 636
  • 1
    `print None` prints "None". I do not think that's what is happening here. – Ankur Agarwal Sep 03 '13 at 15:18
  • 3
    @abc, You're not calling `__instancecheck__` directly. (It is called internally by `isinstance`). Add `return True` at the end of `__instancecheck__`, then try `print isinstance(a, ...)`. – falsetru Sep 03 '13 at 15:20
  • 2
    @abc `isinstance` coerces the result of `__instancecheck__` to bool. – Random832 Sep 03 '13 at 15:32
  • What you answered is not strictly *wrong*, but it's not really the heart of the problem either. Correct usage is `isinstance(a, A)` with the hook defined on the *metaclass*. This answer is pretty confused! – wim Jun 19 '19 at 00:34
3

The __instancecheck__ magic should be defined on the metaclass, not on the class itself. See the docs:

Note that these methods are looked up on the type (metaclass) of a class. They cannot be defined as class methods in the actual class.

The curious behavior you're seeing is by misplacing the isinstance arguments. You wrote:

isinstance(a, a)

But it should really be:

isinstance(a, A)

Now, here's the comedy of errors: if you've mistakenly defined __instancecheck__ as a method on a normal class, instances of the class can accidentally be used as the second argument of isinstance (normally the second arg would be the class object). Python doesn't really care if the second argument's type is a class or a metaclass, because that's just duck-typing in action.

Note that isinstance coerces the return value of __instancecheck__ to boolean. Invoking directly with a.__instancecheck__(a) will return the None.

wim
  • 338,267
  • 99
  • 616
  • 750
  • 1
    It's worth noting that for correct usage `isinstance(a, A)` the `__instancecheck__` won't be called since it's an exact type match and so a shortcut is taken (see [this issue](https://bugs.python.org/issue35083)). – a_guest Sep 30 '20 at 12:08