Search code examples
pythongrammarcpython

How does the python determine the appropriate metaclass?


I maybe find the answer in official doc, but I still can not get it. Can you give me a more detailed or straight forward explanation in the second and third case? I will appreciate it if you could give me some examples!

The appropriate metaclass for a class definition is determined as follows:

  • if no bases and no explicit metaclass are given, then type() is used;
  • if an explicit metaclass is given and it is not an instance of type(), then it is used directly as the metaclass;
  • if an instance of type() is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used.

Solution

  • Let's think you trying to implement the pattern of Singleton by a metaclass (in this case by two of them).

    class Singleton(type):
        _inst = {}
    
        def __call__(cls, *args, **kwargs):
            return cls._inst.setdefault(cls, super().__call__(*args, **kwargs))
    
    class Singleton2(Singleton):
        def __call__(cls, *args, **kwargs):
            return super().__call__(*args, **kwargs)
    
    
    
    class SingletonClass1(metaclass=Singleton):
        pass
    
    
    class SingletonClass2(SingletonClass1, metaclass=Singleton2):
        pass
    
    
    class SingletonClass3():
        pass
    
    
    class SingletonClass4(SingletonClass2, metaclass=Singleton):
        pass
    

    type(class_obj) function returns the metaclass of class_obj.

    So here's your cases:

    1. if no bases and no explicit metaclass are given, then type() is used;

      type(SingletonClass3) --> <class 'type'>

    2. if an explicit metaclass is given and it is not an instance of type(), then it is used directly as the metaclass;

    `type(SingletonClass2) --> <class '__main__.Singleton2'>`
    

    3. if an instance of type() is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used;

    `type(SingletonClass4) --> <class '__main__.Singleton2'>`
    

    If you inherit SingletonClass2 from SingletonClass1 but forget to inherit Singleton2 from Singleton, it'll cause TypeError.

    The most derived metaclass is one which is a subtype of all of these candidate metaclasses. If none of the candidate metaclasses meets that criterion, then the class definition will fail with TypeError.

    Update: Metaclasses can be functions, that are not instances of type, so the second case (if an explicit metaclass is given and it is not an instance of type) can be related to this. Here's Singleton implementation by a metaclass function.

    def singleton_func(class_name, bases, attrs):
        _inst = {}
    
        def custom_new(cls):
            return _inst.setdefault(cls, object.__new__(cls))
    
        attrs['__new__'] = custom_new
        return type(class_name, bases, attrs)
    
    
    class SingletonClass5(metaclass=singleton_func):
        pass