显式继承 'type' 以在 python3.x 中实现元类

Explicitly inheriting from 'type' to implement metaclass in python3.x

我试图在 Python 中获得一些关于 metaclass 的直觉。 Python2.7 和 Python3.5 我都试过了。在 Python3.5 中,我发现我们定义的每个 class 都是 <class 'type'> 类型,无论我们是否显式继承。但是,如果不是从 type 继承的,我们就不能将 class 用作另一个 class.

的 metaclass
>>> class foo:
    pass

>>> class Metafoo(type):
    pass

>>> foo
<class '__main__.foo'>
>>> Metafoo
<class '__main__.Metafoo'>
>>> type(foo)
<class 'type'>
>>> type(Metafoo)
<class 'type'>
>>> 
>>> class foocls1(metaclass=foo):
    pass

执行上述操作时出现以下错误:

Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    class foocls1(metaclass=foo):
TypeError: object() takes no parameters

但是使用 Metafoo 作为新 class

的元class 时情况并非如此
>>> class foocls3(metaclass=Metafoo):
    pass

>>> foocls3
<class '__main__.foocls3'>
>>> type(foocls3)
<class '__main__.Metafoo'>

如果我们想在其他 class.

中使用 class 作为 metaclass,谁能解释为什么我们需要显式继承

"type" 是 Python 3 和 Python 2 post 版本 2.2 中所有 class 对象的基础 class。 (只是在 Python 2 上,你应该从对象继承。 类 在 Python 2 中没有显式继承自 "object" 的被称为 "old style classes",并出于向后兼容的目的而保留,但用处不大。)

所以,发生的事情是继承:class 的超class 和 "since in Python a class is an object itself, what is the class of that object" 的 "metaclass" 是两个不同的东西。您继承的 classes 定义了 class 实例上的属性(和方法)查找顺序,因此您有一个共同的行为。

metaclass 更像是 "the class your class is built with",虽然它可以用于其他目的,但最常用于修改 classes 本身的构造步骤。四处搜索,您会发现 metaclasses 主要实现了 __new____init__ 方法。 (虽然那里有其他方法也可以,但你必须知道你在做什么)

碰巧要构建一个 class 需要一些构建普通对象不需要的操作。这些操作在本机代码层(C Python 中的 C)执行,甚至无法在纯 Python 代码中重现,例如填充 class 的特殊方法槽 - 指针实现 __add____eq__ 等方法的函数。在 CPython 中唯一做到这一点的 class 是 "type"。因此,任何您想用来构建 class 的代码,即作为元 class,都必须在某个时候调用 type.__new__ 方法。 (就像任何你想在 Python 中创建新对象的东西都会在某个时候调用 object.__new__ 中的代码)。

你的错误发生不是因为Python去检查你是否提前直接或间接调用了type.__new__。错误:"TypeError: object() takes no parameters" 仅仅是因为 metaclass 的 __new__ 方法传递了 3 个参数(名称、基数、命名空间),而 [=20= 中的相同方法] 没有传递任何参数。 (两者都得到额外的"cls",也相当于自己,但这不算)。

您可以使用任何可调用函数作为元class,甚至是普通函数。只是它必须采用 3 个显式参数。从那时起,无论此可调用 returns 用作 class,但是如果在某个时候您不调用 type.__new__(甚至间接调用),则您没有有效的class 到 return.

例如,可以创建一个简单的方法,以便能够使用 class 主体作为字典声明:

def dictclass(name, bases, namespace):
    return namespace

class mydict(metaclass=dictclass):
    a = 1
    b = 2
    c = 3

mydict["a"] 

所以,一个有趣的事实是 type 是它自己的元 class。 (这是在 Python 实现中硬编码的)。但是 type 本身也 从对象继承

In [21]: type.__class__
Out[21]: type

In [22]: type.__mro__
Out[22]: (type, object)

并且只是为了结束这个:可以创建 classes 而不调用 type.__new__ 和对象而不调用 object.__new__,但是通常不是来自纯 Python 代码,因为必须为这两个操作填充 C-API 级别的数据结构。可以通过函数的本机代码实现来实现它,也可以使用 ctypes 对其进行破解。