gpt4 book ai didi

python - 习惯从类型继承元类?

转载 作者:IT老高 更新时间:2023-10-28 22:08:31 28 4
gpt4 key购买 nike

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

据我所知,它们都会做同样的事情。有什么理由改用基类吗?习惯吗?

最佳答案

存在细微差别,主要与继承有关。当使用一个函数作为元类,生成的类实际上是 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'>

已经注意到不同之处:创建 Sub1 时调用了 M1,并且两者类是 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'>

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

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

关于python - 习惯从类型继承元类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2149846/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com