python 如何确定合适的元类?

How does the python determine the appropriate metaclass?

我可能在official doc中找到了答案,但我还是得不到。在第二种和第三种情况下,你能给我更详细或更直接的解释吗?如果你能给我一些例子,我将不胜感激!

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.

假设您试图通过元类(在本例中为其中的两个)来实现单例模式。

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) 函数 returns class_obj 的元类。

这是您的案例:

  1. 如果没有给出基类和显式元类,则使用 type();

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

2.如果给出了一个显式的元类,并且它不是type()的实例,那么直接作为元类使用;

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

3. 如果 type() 的实例作为显式元类给出,或者定义了基类,则使用最派生的元类;

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

如果你从SingletonClass1继承了SingletonClass2,却忘记从Singleton继承Singleton2,会导致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.

更新: 元类可以是函数,不是 type 的实例,因此第二种情况(如果给出了显式元类并且它不是类型 的实例)可以与这个。这是元类函数的 Singleton 实现。

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