Python 从类型继承元类的习惯?

Python 从类型继承元类的习惯?,python,metaclass,Python,Metaclass,我一直在试图理解python元类,因此一直在阅读一些示例代码。据我所知,Python元类可以是任何可调用的。所以,我可以让我的元类 def metacls(clsName, bases, atts): .... return type(clsName, bases, atts) 但是,我看到很多人用以下方式编写元类: class Metacls(type): def __new__(meta, clsName, bases, atts): ....

我一直在试图理解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)

据我所知,这两个都会做同样的事情。是否有理由改用基类?这是习惯吗?

有细微的差别,主要与继承有关。当使用 函数作为元类,生成的类实际上是
类型的实例
, 可以不受限制地继承;然而,元类函数 永远不会为此类子类调用。使用
类型的子类
作为 元类,结果类将是该元类的一个实例,如下所示 其任何一个子类;但是,多重继承将受到限制

说明不同之处:

>>> 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'>
这是对元类多重继承的主要限制。 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'>
>M3类(M1,M2):
>>>定义(元、名称、基数、附件):
>>>打印“M3调用”+名称
>>>返回超级(M3,meta)。\uuuu新的\uuuuu(meta,名称,基础,附件)
>>>C3类(C1、C2):
>>>元类=M3
M3需要C3
M1需要C3
M2需要C3
>>>类型(C3)
这就是为什么我在元类
\uuuu new\uuuu
函数中使用了
super()
:所以每个 我可以打电话给MRO的下一个

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

谢谢您花时间解释。非常感谢,我很少看到如此清晰的答案。
>>> 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
>>> 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'>