我试图对Python中的元类有一些直觉。我试过Python2.7和Python3.5。在Python3.5中,我发现我们定义的每个类都是<class '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
我得到以下错误:
^{pr2}$但在使用Metafoo作为新类的元类时,情况并非如此
^{3}$有谁能解释一下,如果我们想在另一个类中使用一个类作为元类,为什么我们需要显式继承这种情况。在
“type”是python3中所有类对象的基类,在python2中是2.2版本之后的所有类对象的基类。(只是在Python2上,您应该从object继承。在Python2中,没有显式继承“object”的类被称为“旧式类”,出于向后兼容的目的而保留,但用处不大。)
所以,发生的是继承:类的超类是什么,而“元类”是“因为在Python中类本身就是一个对象,那么这个对象的类是什么”是两个不同的东西。从中继承的类定义了类实例上属性(和方法)查找的顺序,因此您有一个共同的行为。在
元类相当于“构建类所用的类”,尽管它可以用于其他目的,但它最常用于修改类本身的构造步骤。搜索一下,您会看到元类主要实现}方法。(虽然有其他方法也可以,但你必须知道你在做什么)
__new__
和{碰巧,为了构建一个类,需要一些构建普通对象不需要的操作。这些操作是在本机代码层(CPython中的C)上执行的,甚至在纯Python代码中是不可复制的,比如填充类的特殊方法slot(指向实现
__add__
、__eq__
)和此类方法的函数的指针。在CPython中唯一这样做的类是“type”。因此,任何要用来构建类的代码,例如作为元类,都必须在某个时刻调用type.__new__
方法。(就像您想在Python中创建一个新对象的任何东西都会在某个时刻调用object.__new__
中的代码一样)。在您的错误发生并不是因为Python提前检查您是否对
type.__new__
进行了直接或间接调用。错误:“TypeError:object()不带参数”只是因为元类的__new__
方法传递了3个参数(名称、基、命名空间),而object
中的相同方法没有传递任何参数。(两者都得到额外的“cls”,也相当于self,但这不算在内)。在您可以使用任何可调用的作为元类,甚至是一个普通函数。只不过,它必须采用3个显式参数。不管这个可调用的返回值从那时起就被用作类,但是如果在某个时刻你没有调用
type.__new__
(甚至是间接调用),你就没有一个有效的类可以返回。在例如,可以创建一个简单的方法,以便能够将类主体用作字典声明:
因此,一个有趣的事实是
^{pr2}$type
是它自己的元类。(在Python实现中是硬编码的)。但是type
本身也从object继承:为了结束这一点:可以在不调用
type.__new__
的情况下创建类,也可以在不调用object.__new__
的情况下创建对象,但通常不是从纯Python代码创建的,因为这两个操作都必须填充C-API级别的数据结构。ctypes可以用一个本机代码来实现它。在相关问题 更多 >
编程相关推荐