Python继承中的元类

本文探讨了Python中继承时元类的工作原理。当创建子类时,元类的执行顺序是先执行子类的元类,再执行父类的元类。子类的元类必须是所有父类元类的子类。通过示例代码展示了元类如何影响类的创建过程,以及不同元类定义方式(如__metaclass__属性和type函数)的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继承中的元类

首先写代码测试的时候发现问题

class MetaClassTest1class(type):

    def __new__(cls, clsname, bases, dct):
        dct['test'] = 1

        return super(MetaClassTest1class, cls).__new__(cls, clsname, bases, dct)

class MetaClassTest2class(type):

    def __new__(cls, clsname, bases, dct):
        dct['test'] = 2

        return super(MetaClassTest2class, cls).__new__(cls, clsname, bases, dct)

class MetaClassTest3class(type):

    def __new__(cls, clsname, bases, dct):
        dct['test'] = 3

        return super(MetaClassTest3class, cls).__new__(cls, clsname, bases, dct)

__metaclass__ = MetaClassTest1class

class Foo():
    __metaclass__ = MetaClassTest2class
    pass

class FooChild(Foo):
    __metaclass__ = MetaClassTest3class
    pass

f = Foo()
print f.test

运行的结果是

TypeError                                 Traceback (most recent call last)
<ipython-input-52-81f8a2dedcb4> in <module>()
     24     pass
     25 
---> 26 class FooChild(Foo):
     27     __metaclass__ = MetaClassTest3class
     28     pass

<ipython-input-52-81f8a2dedcb4> in __new__(cls, clsname, bases, dct)
     18         dct['test'] = 3
     19 
---> 20         return super(MetaClassTest3class, cls).__new__(cls, clsname, bases, dct)
     21 
     22 class Foo():

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

也就是子类的元类必须是所有的父类元类的子类(但是并不要求是直接子类)!而这里我们的FooChild的元类为MetaClassTest3class,并不是Foo的元类的子类。修改MetaClassTest3class为MetaClassTest2class的子类,同时我们在元类中进行输出,查看元类具体的运行过程

class MetaClassTest1class(type):

    def __new__(cls, clsname, bases, dct):
        if 'test' in dct:
            print 'MetaClassTest1class test in dct', dct['test']
        dct['test'] = 2
        dct['test'] = 1
        print dct['test']
        return super(MetaClassTest1class, cls).__new__(cls, clsname, bases, dct)

class MetaClassTest2class(type):

    def __new__(cls, clsname, bases, dct):
        if 'test' in dct:
            print 'MetaClassTest2class test in dct', dct['test']
        dct['test'] = 2
        print 'MetaClassTest2class', dct['test']
        return super(MetaClassTest2class, cls).__new__(cls, clsname, bases, dct)


class MetaClassTest3class(MetaClassTest2class):

    def __new__(cls, clsname, bases, dct):
        if 'test' in dct:
            print 'MetaClassTest3class test in dct ', dct['test']
        dct['test'] = 3
        print 'MetaClassTest3class', dct['test']

        return super(MetaClassTest3class, cls).__new__(cls, clsname, bases, dct)

__metaclass__ = MetaClassTest1class

class Foo():
    __metaclass__ = MetaClassTest2class
    pass

class FooChild(Foo):
    __metaclass__ = MetaClassTest3class
    pass

f = FooChild()
print 'final test val', f.test

输出为

MetaClassTest2class 2
MetaClassTest3class 3
MetaClassTest2class test in dct 3
MetaClassTest2class 2
final test val 2

所以可以看到实际上会执行的过程是这样的:

  1. 代码执行到class Foo()的时候,Foo的元类会执行,生成类Foo,这时候print语句输出MetaClassTest2class 2
  2. 代码执行到class FooChild()的时候,FooChild的元类会执行,这时候test为3,print语句输出MetaClassTest3class 3,然后到父类Foo的元类执行,在给test赋值之前已经存在test了,所以print语句输出MetaClassTest2class test in dct 3,然后给test赋值为2,print语句输出为MetaClassTest2class 2,所以最终的test的值为2

从上面来看,子类的__new__的执行和__init__类似,都会先执行子类的,再执行父类的。我们测试一下其它类型的元类定义是否会有这样的现象发生。

class MetaClassTest1class(type):

    def __new__(cls, clsname, bases, dct):
        if 'test' in dct:
            print 'MetaClassTest1class test in dct', dct['test']
        dct['test'] = 1
        print dct['test']
        return super(MetaClassTest1class, cls).__new__(cls, clsname, bases, dct)

class MetaClassTest2class(type):

    def __new__(cls, clsname, bases, dct):
        if 'test' in dct:
            print 'MetaClassTest2class test in dct', dct['test']
        dct['test'] = 2
        print 'MetaClassTest2class', dct['test']
        return super(MetaClassTest2class, cls).__new__(cls, clsname, bases, dct)


class MetaClassTest3class(MetaClassTest2class):

    def __new__(cls, clsname, bases, dct):
        if 'test' in dct:
            print 'MetaClassTest3class test in dct ', dct['test']
        dct['test'] = 3
        print 'MetaClassTest3class', dct['test']

        return super(MetaClassTest3class, cls).__new__(cls, clsname, bases, dct)

def test_inherite(future_class_name, future_class_parents, future_class_attr):
    if 'test' in future_class_attr:
        print 'test in future_class_attr ', future_class_attr['test']
    future_class_attr['test'] = 4
    print future_class_attr['test']
    return type(future_class_name, future_class_parents, future_class_attr)

__metaclass__ = MetaClassTest1class

class Foo():
    __metaclass__ = test_inherite
    pass

class FooChild(Foo):
    pass

f = FooChild()
print 'final test val', f.test

print FooChild.__metaclass__

输出为

4
final test val 4
<unbound method FooChild.test_inherite>

这时候可以看到,子类的__metaclass__为test_inherite,是继承了父类的元类的。

Foo = type('Foo', (), {'test': 1})

FooChild = type('FooChild', (Foo,), {'test': 2})

f = Foo()
print f.test
fc = FooChild()
print fc.test
print Foo.__metaclass__

输出为

1
2
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-93-be60cc74b7d9> in <module>()
      8 fc = FooChild()
      9 print fc.test
---> 10 print Foo.__metaclass__

AttributeError: type object 'Foo' has no attribute '__metaclass__'

可以看到,利用type生成的类,并没有__metaclass__属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值