zoukankan      html  css  js  c++  java
  • python基础----元类metaclass

    1 引子

    class Foo:
        pass
    
    f1=Foo() #f1是通过Foo类实例化的对象

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

    上例可以看出f1是由Foo这个类产生的对象,而Foo本身也是对象,那它又是由哪个类产生的呢?

    #type函数可以查看类型,也可以用来查看对象的类,二者是一样的
    print(type(f1)) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
    print(type(Foo)) # 输出:<type 'type'> 

    2 什么是元类?

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

    元类是用来控制如何创建类的,正如类是创建对象的模板一样

    元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例Foo类是 type 类的一个实例)

    type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象

    3 创建类的两种方式

    方式一:

    class Foo:
        def func(self):
            print('from func')

    方式二:

    def func(self):
            print('from func')
    x=1
    Foo=type('Foo',(object,),{'func':func,'x':1})

    4 一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类(顺便我们也可以瞅一瞅元类如何控制类的创建,工作流程是什么)

    class Mytype(type):
        def __init__(self,class_name,bases=None,dict=None):
            print("Mytype init--->")
            print(class_name,type(class_name))
            print(bases)
            print(dict)
    
        def __call__(self, *args, **kwargs):
            print('Mytype call---->',self,args,kwargs)
            obj=self.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return obj
    
    class Foo(object,metaclass=Mytype):#in python3
        #__metaclass__ = MyType #in python2
        x=1111111111
        def __init__(self,name):
            self.name=name
    
        def __new__(cls, *args, **kwargs):
            return super().__new__(cls)
            # return object.__new__(cls) #同上
    
    
    f1=Foo('name')
    print(f1.__dict__)
    
    自定制元类
    自定制元类
    class Mytype(type):
        def __init__(self,what,bases=None,dict=None):
            print('mytype init')
    
        def __call__(self, *args, **kwargs):
            obj=self.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return obj
    
    class Foo(object,metaclass=Mytype):
        x=1111111111
    
        def __init__(self,name):
            self.name=name
    
        def __new__(cls, *args, **kwargs):
            return super().__new__(cls)
    
    f1=Foo('egon')
    
    print(f1.__dict__)
    
    自定制元类纯净版
    自定制元类纯净版
    class Mytype(type):
        def __init__(self,what,bases=None,dict=None):
            print(what,bases,dict)
    
        def __call__(self, *args, **kwargs):
            print('--->')
            obj=object.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return obj
    class Room(metaclass=Mytype):
        def __init__(self,name):
            self.name=name
    
    r1=Room('alex')
    print(r1.__dict__)
    
    自定制元类精简版
    自定制元类精简版
    #元类总结
    class Mymeta(type):
        def __init__(self,name,bases,dic):
            print('===>Mymeta.__init__')
    
    
        def __new__(cls, *args, **kwargs):
            print('===>Mymeta.__new__')
            return type.__new__(cls,*args,**kwargs)
    
        def __call__(self, *args, **kwargs):
            print('aaa')
            obj=self.__new__(self)
            self.__init__(self,*args,**kwargs)
            return obj
    
    class Foo(object,metaclass=Mymeta):
        def __init__(self,name):
            self.name=name
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls)
    
    '''
    需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__
    
    而爹.__call__一般做两件事:
    1.调用name.__new__方法并返回一个对象
    2.进而调用name.__init__方法对儿子name进行初始化
    '''
    
    '''
    class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行
    Foo=Mymeta('foo',(...),{...})
    因此我们可以看到,只定义class就会有如下执行效果
    ===>Mymeta.__new__
    ===>Mymeta.__init__
    实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,
    遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法
    于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化
    '''
    
    '''
    obj=Foo('egon')
    的原理同上
    '''
    
    '''
    总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
    1.谁后面跟括号,就从谁的爹中找__call__方法执行
    type->Mymeta->Foo->obj
    Mymeta()触发type.__call__
    Foo()触发Mymeta.__call__
    obj()触发Foo.__call__
    2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
    '''
    元类总结

    笔记:

    class People:
        def __init__(self,name):
            self.name=name
    
    
    p=People('egon')
    
    
    # print(type(p))
    #
    # print(type(People))
    
    #typer--->类------>对象
    
    
    
    class Foo:
        x=1
        def run(self):
            pass
    print(type(Foo))
    
    
    
    #type成为元类,是所有类的类,利用type模拟class关键字的创建类的过程
    def run(self):
        print('%s is runing' %self.name)
    
    class_name='Bar'
    bases=(object,)
    class_dic={
        'x':1,
        'run':run
    }
    
    Bar=type(class_name,bases,class_dic)
    print(Bar)
    print(type(Bar))
    元类
    class Foo(metaclass=type):
        x=1
        def run(self):
            print('running')
    
    type('Foo',(object,),{'x':1,'run':run})
    
    
    
    class Mymeta(type):
         def __init__(self,class_name,class_bases,class_dic):
             # print(self)
             # print(class_name)
             # print(class_bases)
             # print(class_dic)
             for key in class_dic:
                if not callable(class_dic[key]):continue
                if not class_dic[key].__doc__:
                    raise TypeError('小子,你没写注释,赶紧去写')
    
             # type.__init__(self,class_name,class_bases,class_dic)
    class Foo(metaclass=Mymeta):
        x=1
        def run(self):
            'run function'
            print('running')
    
    Foo=Mymeta('Foo',(object,),{'x':1,'run':run})
    
    print(Foo.__dict__)
    
    
    
    
    class Mymeta(type):
         def __init__(self,class_name,class_bases,class_dic):
                pass
         def __call__(self, *args, **kwargs):
            # print(self)
            obj=self.__new__(self)
            self.__init__(obj,*args,**kwargs) #obj.name='egon'
            return obj
    class Foo(metaclass=Mymeta):
        x=1
        def __init__(self,name):
            self.name=name #obj.name='egon'
        def run(self):
            'run function'
            print('running')
    # print(Foo.__dict__)
    
    f=Foo('egon')
    
    print(f)
    
    print(f.name)
    元类的自定制
  • 相关阅读:
    腾信短信接口实例
    ajax
    jquery
    生命鸡汤
    sql中事物
    ajax,一般处理程序,登陆
    CSS选择器大全
    【JavaScript】轮播图
    【DOM练习】淘宝购物车
    【DOM练习】百度历史搜索栏
  • 原文地址:https://www.cnblogs.com/wangyongsong/p/6763157.html
Copyright © 2011-2022 走看看