python高级(元类、自定义元类)

什么是元类(metaclass)?

元类是类的类,是类的模板

元类的实例为类,正如类的实例为对象

class Foo:
     pass

t1=Foo() #t1是通过Foo类实例化的对象

print(type(f1))
print(type(Foo))

所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象t1是调用FOO类得到的一个实例。

如果一切皆为对象,那么类Foo本质也是一个对象,既然所有的对象都是调用类得到的,那么Foo必然也是调用了一个类得到的,这个类称为元类。

于是可以推导出===>产生Foo的过程一定发生了:Foo=元类(...)

print(type(Foo)) # 结果为<class 'type'>,证明是调用了type这个元类而产生的Foo,即默认的元类为type



Foo类就是type类的一个实例

我们基于python中一切皆为对象,字符串、列表、字典、函数是对象,类也是一个对象的概念分析出:我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类(元类可以简称为类的类),内置的元类为type,type是Python的一个内建元类,用来直接控制生成类,Python中任何class定义的类其实都是type类实例化的对象。

class关键字在帮我们创建类时,必然帮我们调用了元类Foo=type(...),那调用type时传入的参数是什么呢?必然是类的关键组成部分,一个类有三大组成部分,分别是

1、类名class_name='Foo'

2、基类们class_bases=(object,)   #继承新式类的父类object

3、类的名称空间class_dic,类的名称空间是执行类体代码而得到的

调用type时会依次传入以上三个参数

综上,class关键字帮我们创建一个类应该细分为以下四个过程

拿到类名:class_name='Foo'

拿到类的基类们:class_bases=(object,)

执行类体代码,拿到类的名称空间:class_dic={......}

调用元类得到类Foo = type(class_name,class_bases,class_dic)

 

自定义元类

一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类

1)最简单的情况

假设有下面的类:

class Foo(object):
     pass

现在,我们不使用class关键字来定义,而使用type,如下:

Foo = type('Foo', (object, ), {})    # 使用 type 创建了一个类对象

上面两种方式是等价的。我们看到,type接收三个参数:

第 1 个参数是字符串 'Foo',表示类名
第 2 个参数是元组 (object, ),表示所有的父类
第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
在上面,我们使用type()创建了一个名为 Foo 的类,然后把它赋给了变量 Foo,我们当然可以把它赋给其他变量,但是,此刻没必要给自己找麻烦。

接着,我们看看使用:

>>> print Foo
<class '__main__.Foo'>
>>> print Foo()
<__main__.Foo object at 0x10c34f250>

 

2)有属性和方法的情况

假设有下面的类:

class Foo(object):
    foo = True
    def greet(self):
        print 'hello world'
        print self.foo

用type来创建这个类,如下:

def greet(self):
    print('hello world')
    print(self.foo)

Foo = type('Foo', (object, ), {'foo': True, 'greet': greet})

上面两种方式的效果是一样的,看下使用:

>>> f = Foo()
>>> f.foo
True
>>> f.greet
<bound method Foo.greet of <__main__.Foo object at 0x10c34f890>>
>>> f.greet()
hello world
True

 

把自定义函数名称写进底层字典里封存

def __init__(self,name,age):

    self.name=name

    self.age=age

def test(self):

    print('=====>')

FFo=type('FFo',(object,),{'x':1,'__init__':__init__,'test':test}) #用元类的方法把类方法里的属性按键值对形式写入到函数底层字典里封存

print(FFo)   #<class '__main__.FFo'>

print(FFo.__dict__) 

f1=FFo('jamfiy',18)

print(f1.name) #jamfiy

f1.test()  #=====>

 

继承的情况

再来看看继承的情况,假设有如下的父类:

class Base(object):
    pass

一般我们用 Base 派生一个 Foo 类,如下:

class Foo(Base):
   foo = True

现在改用type来创建,如下:

Foo = type('Foo', (Base, ), {'foo': True})

f1 = Foo()

print(f1.foo)

 

在父类中声明继承元类,子类再继承是元类的父类

例:

class MyType(type):  #声明继承元类type
    def __init__(self,a,b,c):    #Foo实例化f1触发__init__方法
        print('元类的构造函数执行')
        # print(a)   #打印self,Foo
        # print(b)   #打印元组()的内容,来自*args传过来的参数
        # print(c)   #打印字典{}的内容,来自**kwargs传过来的参数
    def __call__(self, *args, **kwargs):   #调用Foo()方法触发__call__方法
        # print('=-======>')
        # print(self)  #Foo
        # print(args,kwargs)
        obj=object.__new__(self)  #调用新式类都继承的object基类,__new__方法生成一个对象引用,object.__new__(Foo)-->f1
        self.__init__(obj,*args,**kwargs)  #相当于执行Foo.__init__(f1,*arg,**kwargs)
        return obj   #返回结果给实例化对象f1
class Foo(metaclass=MyType):  # 继承MyType元类,Foo=MyType(Foo,'Foo',(),{})  ---》 __init__
    def __init__(self,name):
        self.name=name   #相当于执行f1.name=name
# print(Foo)
f1=Foo('alex')
print(f1)
print(f1.__dict__)
————————————————
版权声明:本文为CSDN博主「旅立の涯秸」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jamfiy/java/article/details/88253058
原文地址:https://www.cnblogs.com/vincent-sh/p/12775700.html