21

I am using python 2.7.3 on Windows. I tried to override the __instancecheck__ magic method as a class method. But I can not make it work.

class Enumeration(int):
    @classmethod
    def __instancecheck__(cls, inst):
        if type(inst) == cls:
            return True
        if isinstance(inst, int) and inst in range(0,10):
            return True
        return False

print isinstance(1, Enumeration)   # prints False
print isinstance(1, Enumeration()) # prints True

I assume the first print statement would get True. But it seems the magic method __instancecheck__ is not called. And I don't know why the second print statement can work since the isinstance should take a class/type as the second parameter.

Does anyone know what the problem is? Thanks.

adarliu
  • 483
  • 1
  • 3
  • 13

2 Answers2

28

instancecheck must be defined in a metaclass:

class Enumeration(type):
    def __instancecheck__(self, other):
        print 'hi'
        return True


class EnumInt(int):
    __metaclass__ = Enumeration

print isinstance('foo', EnumInt) # prints True

Why is that? For the same reason why your second example worked. When python evaluates isinstance(A, B) it assumes B to be an object, looks for its class and calls __instancecheck__ on that class:

isinstance(A, B):
    C = class-of(B)
    return C.__instancecheck__(A)

But when B is a class itself, then its class C should be a class of a class, in other words, a meta-class!

georg
  • 211,518
  • 52
  • 313
  • 390
8

The docs say:

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. This is consistent with the lookup of special methods that are called on instances, only in this case the instance is itself a class.

http://docs.python.org/2/reference/datamodel.html#customizing-instance-and-subclass-checks

Kos
  • 70,399
  • 25
  • 169
  • 233