zoukankan      html  css  js  c++  java
  • 元类

    1. 元类是什么

    # 一切皆对象:类实际上一个一个对象
    # Penson类也是个对象,那他一定是由一个类实例化得到,这个类,就叫元类
    # type是内置的一个元类,所有的类都是由type实例化得到
    # 产生类的类,叫元类
    
    class Person:
        def __init__(self,name):
            self.name = name
        def score(self):
            print('分数是100')
    
    p = Person('nick')
    
    a = Person
    p1 = a('nick')
    print(p1.name)
    
    # 如何找元类
    print(type(p))
    # 同理:type类是产生所有类的元类
    print(type(Person))
    print(type(dict))
    print(type(list))
    print(type(str))
    print(type(object))
    
    print(type(type))
    

    2. class底层原理分析

    
    # class 类名   会把类构造出来
    # 实际上是:元类实例化产生类 这个对象
    # 类实例化产生对象,一定是:类名()
    # Person 类是由type实例化产生,传一堆参数
    # type() 调用类的__init__方法
    # type()
    # type(object_or_name,bases,dict)
    # object_or_name:类的名字,是个字符串
    # bases:是他的所有父类,基类
    # dict:名称空间,是一个字典
    
    # 通过type来直接产生类,不用class关键字了
    l = {}
    exec('''
    school = 'oldboy'
    def __init__(self,name):
        self.name = name
    def score(self):
        print('分数是100')
    ''',{},l)
    def __init__(self,name):
        self.name = name
    
    # Person = type('Person',(object,),{'school':'oldboy','__init__':__init__})
    
    Person = type('Person',(object,),l)
    
    print(Person.__dict__)
    print(Person.__bases__)
    
    p = Person('nick')
    print(p.name)
    print(p.__dict__)
    
    # class 底层就是调用type来实例化产生类(对象)
    
    class Person:
        school = 'oldboy'
        def __init__(self,name):
            self.name = name
        def score(self):
            print('分数是100')
    a = Person
    p = Person('nick')
    print(p.name)
    
    # exec()  eval() 的区别
    l = {}
    exec('''
    school = 'oldboy'
    def __init__(self,name):
        self.name = name
    def score(self):
        print('分数是100')
    ''',{},l)
    
    print(l)
    
    g = {'x':1,'y':2}
    l = {}
    exec('''
    global x
    x = 100
    z = 200
    m = 300
    ''',g,l)
    print(g)
    print(l)
    

    3. 通过元类来控制类的产生

    # 自定义元类:来控制类的产生:可以控制类名,可以控制类的继承父类,控制类的名称空间
    
    # type
    # 自定义元类必须继承type,写一个类继承type  这种类都叫元类
    
    class Mymeta(type):
        # def __init__(self,*args,**kwargs):
        def __init__(self,name,bases,dic):
            # self就是Person类
            print(name)
            print(bases)
            print(dic)
            # 练习一:加限制 控制类名必须以sb开头
            if not name.startswith('sb'):
                raise Exception('类名没有以sb开头')
            # 练习二:类必须加注释
            print(self.__dict__['__doc__'])
    
    # metaclass = Mymeta 指定这个类生成的时候,用自己写的Mymeta这个元类
    class Person(object,metaclass=Mymeta):
        '''
        注释
        '''
        school = 'oldboy'
        def __init__(self,name):
            self.name = name
        def score(self):
            print('分数是100')
    
    p = Person()
    
    class Mymeta(type):
        def __init__(self,name,bases,dic):
            print(self.__dict__['__doc__'])
            doc = self.__dict__['__doc__']
            if not doc:
                # 没有加注释
                raise Exception('你的类没有加注释')
    class Person(object,metaclass=Mymeta):
        '''
        我加了注释
        '''
        school = 'oldboy'
        def __init__(self,name):
            self.name = name
        def score(self):
            print('分数是100')
    

    4. 通过元类控制类的调用过程

    # __call__
    # 控制类的调用过程,实际上在控制 对象的产生
    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            # print('xxx')
            return 1
    
    class Person(object,metaclass=Mymeta):
        school = 'oldboy'
        def __init__(self,name):
            self.name = name
        def score(self):
            print('分数是100')
    
    # p = Person('nick')
    # print(p.name)
    
    class Person():
        school = 'oldboy'
        def __init__(self,name):
            self.name = name
        def score(self):
            print('分数是100')
        def __call__(self, *args, **kwargs):
            print('xxx')
    
    p = Person('nick')  # 自动触发init的执行
    # 先触发元类的__call__
    p()
    
    # __new__
    
    # 练习:把对象中的所有属性都设置成私有的
    # 分析
    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            # self是Person这个类
            print(args)
            print(kwargs)
            # return self(*args)  # 这里不行,会递归
            self.__new__(self)
            # 实例化产生一个Person类的对象,借助__new__来产生,需要把类传过去,才能产生对象
            # obj是Person类的对象,只不过是空的
            obj = object.__new__(self)
            # obj = self.__new__(self)
            # 调用__init__方法完成初始化
            # 类来调用__init__方法,就是个普通函数,有几个参数就传几个参数
            # self.__init__(*args,**kwargs)
            # 对象来调用__init__方法,对象的绑定方法,就会把自身传过来
            obj.__init__(*args,**kwargs)
            print(obj)
            return obj
    
    
    class Person(object,metaclass=Mymeta):
        school = 'oldboy'
        def __init__(self,name):
            self.name = name
        def score(self):
            print('分数是100')
    
    p = Person(name = 'nick')
    print(p)
    print(p.name)
    
    # 把对象所有的属性都变成私有
    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            obj = object.__new__(self)
            obj.__init__(*args,**kwargs)
            print(obj.__dict__)
            obj.__dict__ = {f'_{self.__name__}__{k}':v for k,v in obj.__dict__.items()}
            print(obj.__dict__)
            return obj
    
    class Person(object,metaclass=Mymeta):
        school = 'oldboy'
        def __init__(self,name):
            self.name = name
        def score(self):
            print('分数是100')
    p = Person(name = 'nick')
    print(p.__dict__)
    # print(p.name)
    print(p)
    # print(p.name)
    

    5. 有了元类之后的属性查找

    # 类的属性查找顺序:先从类本身中找--->mro继承关系去父类中找--->去自己定义的元类中找--->type中找--->报错
    # 对象的属性查找顺序:先从对象自身找--->类中找--->mro继承关系去父类中找--->报错
    
    class Mymeta(type):
        n=444
    
        def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'>
            obj=self.__new__(self)
            # print(self.__new__ is object.__new__) #True
            obj.__init__(*args, **kwargs)
            return obj
    
    
    class Bar(object):
        # n=333
        pass
    
        # def __new__(cls, *args, **kwargs):
        #     print('Bar.__new__')
    
    class Foo(Bar):
        # n=222
        pass
    
        # def __new__(cls, *args, **kwargs):
        #     print('Foo.__new__')
    
    class oldboyTeacher(Foo,metaclass=Mymeta):
        # n=111
    
        school='oldboy'
    
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def say(self):
            print('%s says welcome to the oldboy to learn Python' %self.name)
    
    
        # def __new__(cls, *args, **kwargs):
        #     print('OldboyTeacher.__new__')
    
    
    o=oldboyTeacher('egon',18) #触发oldboyTeacher的类中的__call__方法的执行,进而执行self.__new__开始查找
    print(oldboyTeacher.n)
    # print(o.n)
    
  • 相关阅读:
    Kibana6.x.x——启动后的一些警告信息记录以及解决方法
    Kibana6.x.x源码开发——执行 yarn start --no-base-path 启动命令后报错
    在Ubuntu中使用AppImage类型文件
    Kibana6.x.x源码分析--启动时basePath
    Kibana 视图开发入门参考文档
    npm install 安装包报错
    git学习--删除远程仓库不存在的分支
    git学习--远程分支删除
    git学习---去除版本控制
    git学习--clone和pull
  • 原文地址:https://www.cnblogs.com/yushan1/p/11453840.html
Copyright © 2011-2022 走看看