Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I redefine the type() of instances of my Python class?

I'm doing some debugging and need to ensure instances of my class have a specific type, e.g. <type 'list'>, when type() is called.

The other option is redefining type() so it returns a different value when instances of my class are passed to it.

For example:

class Test:
    def __str__(self):
        return 'anything'

allows me to set my own value when the instance is treated as a string e.g. str(Test()). I want something similar for type(Test()):

class Test:
    def __type__(self):
        return type([])

(not valid)

like image 712
Qgenerator Avatar asked Dec 04 '25 15:12

Qgenerator


1 Answers

One way to achieve this is to use meta classes and define types. Here's a simple example of how you can do that.

Meta class definition and inheritance

# Meta class
class TypeClass(type):
        def __new__(cls, *args, **kwargs):
                return super(TypeClass, cls).__new__(cls, *args, **kwargs)

        def __init__(self, *args, **kwargs):
                super(TypeClass, self).__init__(*args, **kwargs)


# Class directly inheriting from the meta class.
class ObjectClass(metaclass=TypeClass):
        pass


# Class that has indirectly inherited from the meta class.
class TestClass(ObjectClass):
        pass

Tests

Let's test our TypeClass:

test = TypeClass
print("mro: {} \ntype: {} \nrepr: {}".format(
          test.__mro__,
          type(test),
          repr(test)
      ))

mro: (<class '__main__.TypeClass'>, <class 'type'>, <class 'object'>) 
type: <class 'type'> 
repr: <class '__main__.TypeClass'>

Now let's test our ObjectClass:

test = ObjectClass
print("mro: {} \ntype: {} \nrepr: {}".format(
          test.__mro__,
          type(test),
          repr(test)
     ))

Displays:

mro: (<class '__main__.ObjectClass'>, <class 'object'>) 
type: <class '__main__.TypeClass'> 
repr: <class '__main__.ObjectClass'>

Finally, let's test our TestClass:

test = TestClass

print("mro: {} \ntype: {} \nrepr: {}".format(
          test.__mro__, 
          type(test), 
          repr(test)
      ))

Displays:

mro: (<class '__main__.TestClass'>, <class '__main__.ObjectClass'>, <class 'object'>) 
type: <class '__main__.TypeClass'> 
repr: <class '__main__.TestClass'>

Answer to the question

So, here is an answer to your question. Although, it would be useful if you say why you're doing this. Perhaps there is a better way for implementing what you're trying to achieve here!

class TypeClass(list):
        def __new__(cls, args):
                return super(TypeClass, cls).__new__(cls, args)

        def __init__(self, args):
                super(TypeClass, self).__init__(args)


# class ObjectClass(metaclass=TypeClass):
#         pass


class TestClass(TypeClass):
        pass


test = TestClass
print("mro: {} \ntype: {} \nrepr: {}".format(
        test.__mro__,
        type(test),
        repr(test)
      ))


tests = {
        'test1': isinstance(TestClass, type(list)),
        'test2': isinstance(TestClass, list),
        'test3': type(TestClass) is type(list),
        'test4': type(TestClass) is list,
        'test5': type(TestClass) is type([]),
        'test6': type(TestClass) == type(list),
        'test7': type(TestClass) == type([]),
        'test8': type(TestClass) == type(type([]))
}

print('\n', *[item for item in tests.items()])

Which displays:

mro: (<class '__main__.TestClass'>, <class '__main__.TypeClass'>, <class 'list'>, <class 'object'>) 
type: <class 'type'> 
repr: <class '__main__.TestClass'>

('test3', True) ('test6', True) ('test4', False) ('test7', False) ('test5', False) ('test2', False) ('test1', True) ('test8', True)
like image 104
Pouria Avatar answered Dec 06 '25 04:12

Pouria