Class / type of class, that was created with metaclass

63 views Asked by At
class Meta(type):
    def __new__(cls, name, bases, dct):
        new_class = type(name, bases, dct)
        new_class.attr = 100  # add some to class
        return new_class


class WithAttr(metaclass=Meta):
    pass


print(type(WithAttr))
# <class 'type'>

Why does it print <class 'type'>, but not <class '__main__.Meta'> Am I right that class WithAttr is instance of Meta?

2

There are 2 answers

0
blhsing On BEST ANSWER

This is because you're making an explicit call to type(name, bases, dct), which in turn calls type.__new__(type, name, bases, dct), with the type class passed as the first argument to the type.__new__ method, effectively constructing an instance of type rather than Meta.

You can instead call type.__new__(cls, name, bases, dct), passing the child class as an argument to contruct a Meta instance. In case __new__ is overridden in a parent class that is a child class of type, call super().__new__ instead of type.__new__ to allow the method resolution order to be followed.

Change:

new_class = type(name, bases, dct)

to:

new_class = super().__new__(cls, name, bases, dct)

Demo: https://ideone.com/KIy2qG

0
Rohan On

This is due to the metaclass assignment and how Python handles metaclasses.

If, within Meta.__new__, we create the instance using super().__new__, the metaclass Meta will properly used to create the class WithAttr:

class Meta(type):
    def __new__(cls, name, bases, dct):
        dct['attr'] = 100 # add an attribute to the class
        return super().__new__(cls, name, bases, dct)


class WithAttr(metaclass=Meta):
    pass


print(type(WithAttr))  # <class '__main__.Meta'>

This works by ensuring that the object returned from __new__ is a Meta instance.