zoukankan      html  css  js  c++  java
  • 12.python-metaclass元类

    1.python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class的时候会创建一个对象(这里的对象指的是类而非类的实例)

    class Foo:                 #class语法后面跟一个类Foo,这个类本身也是一个对象
          pass
    
    #f1是通过Foo类实例化的对象
    f1=Foo()
    #通过type查看f1这个对象由哪一个类产生
    print(type(f1))           #输出:<class '__main__.Foo'>    f1这个对象由Foo类创建
    #通过type查看Foo这个类由哪一个对象产生
    print(type(Foo))          #输出:<class 'type'>            Foo这个类的类是type,type是python的一个内置元类

    返回:
    <class '__main__.Foo'>
    <class 'type'>
    2.什么是元类(用来产生class后面定义那个类的类)
    (1)元类是类的类,是类的模版
    (2)元类是用来控制如何创建类的,正如类是创建对象的模版一样
    (3)元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是type类的一个实例)
    (4)typy是python的一个内建元类(不指定类的类是谁默认用typy去生成),用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
    3.创建元类的两种方式
    方式一:利用关键字的方式声明一个类

    class Foo:
        def __init__(self):    #加上构造函数__init__
            pass
    
    #查看Foo这个类
    print(Foo)
    #查看Foo这个类里的属性
    print(Foo.__dict__)

    返回:
    class '__main__.Foo'>
    {'__module__': '__main__', '__init__': <function Foo.__init__ at 0x00399858>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
    方式二:直接用type的方式直接实例化一个结果,这个结果相当于class声明的类

    def __init__(self,name,age):   #顶级作用域里定义构造函数__init__
        self.name=name
        self.age=age
    
    def test(self):               #创造test方法
        print('我是test方法')
    
    #创建元类FFo是由type类产生的
    FFo=type('FFo',(object,),{'x':1,'__init__':__init__,'test':test})    #实例化type传三个参数进去,参数1:类名字符串形式,参数2:继承的父类元祖的形式(新式类默认object),参数3:类的属性'x':1和方法属性__init__':__init__和test':test放在属性字典里
    #查看Foo这个类
    print(FFo)
    #用FFo这个对象产生实例传俩个参数xixi和18
    f1=FFo('xixi',18)
    #调f1的x的类属性
    print(f1.x)        #返回:1
    #调f1的name的类属性
    print(f1.name)     #返回:xixi
    #调f1的方法实例化
    f1.test()          #返回:我是test方法
    #查看Foo这个类里的属性
    print(FFo.__dict__)

    返回:
    <class '__main__.FFo'>
    1
    xixi
    我是test方法
    {'x': 1, '__init__': <function __init__ at 0x01D8C6A8>, 'test': <function test at 0x02109858>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'FFo' objects>, '__weakref__': <attribute '__weakref__' of 'FFo' objects>, '__doc__': None}
    4.一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类
    5.自定制元类控制实例的生成过程

    #定制元类必MyType须继承type类
    class MyType(type):
        def __init__(self,a,b,c):               #第二步:接收metaclass=MyType传来的四个参数,得到结果Foo,Foo这个类就此生成结束运行
            print('触发元类的构造函数执行')
            #print(a)                           #参数二传过来的类名
            #print(b)                           #参数三传过来继承的object
            #print(c)                           #参数四传过来类的属性字典
    
        def __call__(self, *args, **kwargs):    #第四步:接收self是Foo本身,*args, **kwargs接收Foo传的参数xixi
            print('触发元类里__call__方法')
            #print(self)                        #查看self是Foo:<class '__main__.Foo'>
            #print(args,kwargs)                 #查看*args, **kwargs传过来的值('xixi',) {}
            obj = object.__new__(self)          #第五步:生成Foo的对象。所有类都继承object,object.__new__就是创建一个新的对象把self传进去,self就是Foo,得到的就是Foo这个对象,Foo产生的对象就是f1赋值给obj
            self.__init__(obj, *args, **kwargs) #第六步:给f1做封装的属性的事。self.__init__相当于执行Foo.__init__ 就是在执行def __init__(self,name):要传俩个参数self传obj就是f1  name传 *args, **kwargs
            return obj                          #第七步:return obj相当于return了f1。__call__得到返回值才赋值给f1
    
    #定义Foo这个类声明它的元类是MyType,只要一class Foo会触发MyType('Foo',(object,),{})
    class Foo(metaclass=MyType):                #第一步:执行class Foo相当于用MyType来实例化Foo,会触发class MyType(type)自己下面的__init__方法,传四个参数给__init__方法
        def __init__(self,name):                #第八步:跳到Foo的__init__方法
            self.name=name                      #第九步:给f1封装属性,name的属性封装到f1的属性字典里。得到f1.name=name
    
    #调用
    f1=Foo('xixi')                              #第三步:用Foo这个类名加上('xixi')在运行这个类,这个类本身就是一个对象,运行Foo('xixi')就是在调用MyType(type):里的__call__方法(因为Foo是MyType产生的)   #第十步:__call__运行完毕代表Foo('xixi') 运行完毕把变量返值回给f1
    #查看f1
    print(f1)
    #查看f1字典里的属性
    print(f1.__dict__)

    返回:
    触发元类的构造函数执行
    触发元类里__call__方法
    <__main__.Foo object at 0x027C49D0>
    {'name': 'xixi'}

  • 相关阅读:
    Jmeter 将正则表达式提取的参数传给全局(跨线程组使用变量)
    pod的状态分析
    前端 -- html介绍和head标签
    Python ----- 线程和进程
    网络编程 ------ 基础
    面向对象相关操作
    面向对象 --- 进阶篇
    python --- 面向对象
    python的模块和包的详细说明
    常用模块------时间模块 , random模块 ,os模块 , sys模块
  • 原文地址:https://www.cnblogs.com/xixi18/p/9894819.html
Copyright © 2011-2022 走看看