习惯从类型继承元类? [英] Customary To Inherit Metaclasses From type?

查看:83
本文介绍了习惯从类型继承元类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图理解python元类,因此一直在研究一些示例代码.据我了解,Python元类可以是任何可调用的.因此,我可以将元类设置为

I have been trying to understand python metaclasses, and so have been going through some sample code. As far as I understand it, a Python metaclass can be any callable. So, I can have my metaclass like

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

但是,我看到很多人都通过以下方式编写元类:

However, I have seen a lot of people write their metaclasses in the following way:

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

据我所见,它们都可以做相同的事情.是否有任何理由使用基类呢?这是习惯吗?

As far as I can see, these would both do the same thing. Is there any reason to use the base class instead? Is it customary?

推荐答案

存在细微的差异,主要与继承有关.当使用 作为元类函数,结果类实际上是type的实例, 可以不受限制地继承;但是,元类函数 此类子类永远不会被调用.当使用type的子类作为 元类,结果类将是该元类的实例, 它的任何子类;但是,多重继承将受到限制.

There are subtle differences, mostly relating to inheritance. When using a function as a metaclass, the resulting class is really an instance of type, and can be inherited from without restriction; however, the metaclass function will never be called for such subclasses. When using a subclass of type as a metaclass, the resulting class will be an instance of that metaclass, as will any of its subclasses; however, multiple inheritance will be restricted.

说明差异:

>>> 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没有元类的方式创建,而是 在创建后就被操纵了.

Note that when defining sub1 and sub2, no metaclass functions were called. They will be created exactly as if c1 and c2 had no metaclasses, but instead had been manipulated after creation.

>>> 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()进行实际的创建, 出于某些原因,稍后将予以阐明.

Note the differences already: M1 was called when creating Sub1, and both classes are instances of M1. I'm using super() for the actual creation here, for reasons which will become clear later.

>>> 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是否是兼容的元类, 因此它会迫使您创建一个新的文件来保证它可以满足您的需求.

This is the major restriction on multiple inheritance with metaclasses. Python doesn't know whether M1 and M2 are compatible metaclasses, so it forces you to create a new one to guarantee that it does what you need.

>>> 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中呼叫下一个.

This is why I used super() in the metaclass __new__ functions: so each one can call the next one in the MRO.

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

Certain use cases might need your classes to be of type type, or might want to avoid the inheritance issues, in which case a metaclass function is probably the way to go. In other cases, the type of the class might be truly important, or you might want to operate on all subclasses, in which case subclassing type would be a better idea. Feel free to use the style that fits best in any given situation.

这篇关于习惯从类型继承元类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆