显式继承“type”以实现python3.x中的元类

2024-09-30 16:25:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图对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}$

有谁能解释一下,如果我们想在另一个类中使用一个类作为元类,为什么我们需要显式继承这种情况。在


Tags: 类型定义foomaintype错误情况pass
1条回答
网友
1楼 · 发布于 2024-09-30 16:25:45

“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__(甚至是间接调用),你就没有一个有效的类可以返回。在

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

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

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

mydict["a"] 

因此,一个有趣的事实是type是它自己的元类。(在Python实现中是硬编码的)。但是type本身也从object继承:

^{pr2}$

为了结束这一点:可以在不调用type.__new__的情况下创建类,也可以在不调用object.__new__的情况下创建对象,但通常不是从纯Python代码创建的,因为这两个操作都必须填充C-API级别的数据结构。ctypes可以用一个本机代码来实现它。在

相关问题 更多 >