习惯于从类型继承元类?

2024-06-01 00:23:55 发布

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

我一直在尝试理解python元类,因此也一直在研究一些示例代码。据我所知,Python元类可以是任何可调用的。所以,我可以像

def metacls(clsName, bases, atts):
    ....
    return type(clsName, bases, atts)

但是,我看到很多人用以下方式编写他们的元类:

class Metacls(type):
    def __new__(meta, clsName, bases, atts):
        ....
        return type.__new__(meta, clsName, bases, atts)

据我所见,这两种方法都是一样的。有没有理由用基类代替?这是惯例吗?


Tags: 代码示例newreturndeftype方式meta
1条回答
网友
1楼 · 发布于 2024-06-01 00:23:55

有一些细微的差别,主要与遗传有关。当使用 函数作为元类,结果类实际上是type的实例, 并且可以不受限制地从继承;但是,元类函数 永远不会为这样的子类调用。当使用type的子类作为 元类,生成的类将是该元类的实例 它的任何子类;但是,多重继承将受到限制。

说明差异:

>>> def m1(name, bases, atts):
>>>     print "m1 called for " + name
>>>     return type(name, bases, atts)
>>>

>>> def m2(name, bases, atts):
>>>     print "m2 called for " + name
>>>     return type(name, bases, atts)
>>>

>>> class c1(object):
>>>     __metaclass__ = m1
m1 called for c1

>>> type(c1)
<type 'type'>

>>> class sub1(c1):
>>>     pass

>>> type(sub1)
<type 'type'>

>>> class c2(object):
>>>     __metaclass__ = m2
m2 called for c2

>>> class sub2(c1, c2):
>>>     pass

>>> type(sub2)
<type 'type'>

注意,在定义sub1和sub2时,没有调用元类函数。 它们将被创建,就像c1和c2没有元类一样,但是 在创造之后被操纵。

>>> class M1(type):
>>>     def __new__(meta, name, bases, atts):
>>>         print "M1 called for " + name
>>>         return super(M1, meta).__new__(meta, name, bases, atts)

>>> class C1(object):
>>>     __metaclass__ = M1
M1 called for C1

>>> type(C1)
<class '__main__.M1'>

>>> class Sub1(C1):
>>>     pass
M1 called for Sub1

>>> type(Sub1)
<class '__main__.M1'>

注意不同之处:M1在创建Sub1时被调用,并且 类是M1的实例。我在这里使用super()进行实际创建, 原因稍后会清楚的。

>>> class M2(type):
>>>     def __new__(meta, name, bases, atts):
>>>         print "M2 called for " + name
>>>         return super(M2, meta).__new__(meta, name, bases, atts)

>>> class C2(object):
>>>     __metaclass__ = M2
M2 called for C2

>>> type(C2)
<class '__main__.M2'>

>>> class Sub2(C1, C2):
>>>     pass
M1 called for Sub2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 23, in __new__
TypeError: Error when calling the metaclass bases
    metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

这是对元类多重继承的主要限制。 Python不知道M1和M2是否是兼容的元类, 所以它迫使你创造一个新的,以保证它做你需要的。

>>> class M3(M1, M2):
>>>     def __new__(meta, name, bases, atts):
>>>         print "M3 called for " + name
>>>         return super(M3, meta).__new__(meta, name, bases, atts)

>>> class C3(C1, C2):
>>>     __metaclass__ = M3
M3 called for C3
M1 called for C3
M2 called for C3

>>> type(C3)
<class '__main__.M3'>

这就是我在元类函数中使用super()的原因:所以每个函数 可以打电话给MRO的下一个。

某些用例可能需要类的类型是type,或者可能需要 为了避免继承问题,在这种情况下,元类函数可能是 去的路。在其他情况下,类的类型可能非常重要, 或者您可能需要对所有子类进行操作,在这种情况下,子类化 type是个更好的主意。随意使用最适合的款式 任何特定的情况。

相关问题 更多 >