在 python3.x 中显式继承“类型”以实现元类
Posted
技术标签:
【中文标题】在 python3.x 中显式继承“类型”以实现元类【英文标题】:Explicitly inheriting from 'type' to implement metaclass in python3.x 【发布时间】:2018-04-26 22:35:26 【问题描述】:我试图对 Python 中的元类有一些直觉。我已经尝试过 Python2.7 和 Python3.5。在 Python3.5 中,我发现我们定义的每个类都是 <class 'type'>
类型,无论我们是否显式继承。但如果不是从 type 继承,我们就不能将该类用作另一个类的元类。
>>> 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 foocls3(metaclass=Metafoo):
pass
>>> foocls3
<class '__main__.foocls3'>
>>> type(foocls3)
<class '__main__.Metafoo'>
如果我们想将一个类用作其他类中的元类,任何人都可以解释为什么我们需要显式继承这种情况。
【问题讨论】:
每个类都是type
的实例,但它们并不是type
的所有子类。
【参考方案1】:
"type" 是 Python 3 和 Python 2 2.2 之后的所有类对象的基类。 (只是在 Python 2 上,您应该从 object 继承。在 Python 2 中没有显式从“object”继承的类被称为“old style classes”,并出于向后兼容的目的而保留,但几乎没有用.)
所以,发生的事情就是继承:类的超类是什么,以及“由于在 Python 中类是对象本身,该对象的类是什么”的“元类”是两个不同的东西。您继承的类定义了对类实例的属性(和方法)查找顺序,因此您有一个共同的行为。
元类是“你的类所用的类”,虽然它可以用于其他目的,但最常用于修改类本身的构造步骤。搜索一下,您会看到主要实现__new__
和__init__
方法的元类。 (虽然可以有其他方法,但是你必须知道你在做什么)
碰巧构建一个类需要一些构建普通对象不需要的操作。这些操作在本机代码层(CPython 中的 C)上执行,甚至无法在纯 Python 代码中重现,例如填充类的特殊方法槽——指向实现 __add__
、__eq__
等的函数的指针方法。在 CPython 中这样做的唯一类是“类型”。因此,您想用来构建类的任何代码,即作为元类,都必须在某个时候调用type.__new__
方法。 (就像你想在 Python 中创建一个新对象一样,在某些时候会调用object.__new__
中的代码。)。
您的错误发生并不是因为 Python 会提前检查您是直接还是间接调用了 type.__new__
。错误:“TypeError:object() 没有参数”仅仅是因为元类的__new__
方法传递了 3 个参数(名称、基数、命名空间),而 object
中的相同方法没有传递参数。 (两者都获得额外的“cls”,也相当于 self,但这不计算在内)。
您可以将任何可调用对象用作元类,甚至是普通函数。只是它必须采用 3 个显式参数。从那时起,无论这个可调用返回什么都用作类,但如果在某些时候您不调用type.__new__
(甚至是间接调用),那么您就没有要返回的有效类。
例如,可以创建一个简单的方法,以便能够将类主体用作字典声明:
def dictclass(name, bases, namespace):
return namespace
class mydict(metaclass=dictclass):
a = 1
b = 2
c = 3
mydict["a"]
所以,一个有趣的事实是type
是它自己的元类。 (在 Python 实现中是硬编码的)。但是type
本身也从对象继承:
In [21]: type.__class__
Out[21]: type
In [22]: type.__mro__
Out[22]: (type, object)
为了结束这一点:可能在不调用 type.__new__
的情况下创建对象,在不调用 object.__new__
的情况下创建对象,但通常不是从纯 Python 代码中创建,作为 C-必须为这两个操作填写 API 级别。可以使用本机代码实现函数来执行此操作,也可以使用 ctypes 对其进行破解。
【讨论】:
感谢您的解释以上是关于在 python3.x 中显式继承“类型”以实现元类的主要内容,如果未能解决你的问题,请参考以下文章