zoukankan      html  css  js  c++  java
  • 元类及其原理

    什么是元类

    在python中,一切都是对象,那么类肯定也是一个一个对象

    如果类是对象的话,那他一定是由一个实例化得到,这个类就叫做元类。也就是说产生类的类,叫做元类

    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))
    

    上述结构都为<class 'type'>,也就是说,在一般情况下,元类为type。type是一个内置的元类,所有的类都是有type实例化得到

    class底层原理分析

    class+类名,会把类构造出来,但是,实际上则是元类实例化产生类这个对象。

    我们也可以用type来直接产生类,而不用class关键字

    type() 掉用类的__init__方法
    type(object_or_name, bases, dict)
    object_or_name:类的名字,是个字符串
    bases:是它的所有父类,基类
    dict:名称空间,

    那么我们就可以定义一个简单的Person类

    def __init__(self,name):
        self.name=name
    Person=type('Person',(object,),{'school':'oldboy','__init__':__init__})
    

    我们也可以用exec()方法来实现最后字典的输入

    l={}
    exec('''
    school='school'
    def __init__(self,name):
        self.name=name
    def score(self):
        print('分数是100')
    ''',{},l)
    Person=type('Person',(object,),l)
    

    通过元类来控制类的产生

    自定义元类,来控制类的产生,可以控制类名,可以控制类的继承父类,控制类的名称空间自定义元类必须继承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开头')
    class sb_Person(object,metaclass=Mymeta):
    
        school='雄英高中'
        def __init__(self,name):
            self.name=name
        def score(self):
            print('分数是100')
    

    如果上述代码类名不以sb开头,则会抛出'类名没有以sb开头'异常

    同样我们也可以办到让类必须添加注释

    查询注释的方法为类名._doc_

    class Mymeta(type):
        def __init__(self,name,bases,dic):
            print(self.__dict__['__doc__'])
            doc=self.__dict__['__doc__']
            if not doc:
                # 没有加注释
                raise Exception('你的类没有加注释')
    #metaclass=Mymeta  指定这个类生成的时候,用自己写的Mymeta这个元类
    class Person(object,metaclass=Mymeta):
        '''
        注释
        '''
        school='音乃木坂学院'
        def __init__(self,name):
            self.name=name
        def score(self):
            print('分数是100')
    

    控制类的调用过程

    控制类的调用过程,实际上是在控制对象的产生

    我们在使用__call__的时候,如果采用对象加()的话,就会调用类里__call__方法

    那么如果我们采用类加()的时候呢?很明显我们会调用元类里的__call__方法

    我们可以因此而不改变类内的东西,只用元类来使该类里的属性隐藏

    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            obj=object.__new__(self)
            # self.__init__(obj,*args, **kwargs)	# 也可以用
            obj.__init__(*args, **kwargs)
            # print(obj.__dict__)
            obj.__dict__={ '_%s__%s'%(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)	# 会报错,因为已经被隐藏
    

    有了元类之后的属性查找顺序

    类的属性查找顺序:先从类本身中找--->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)
    
  • 相关阅读:
    pormise的基本用法
    let 与 var 的区别
    字符串
    数组
    Redis 低级数据结构:一、介绍
    Curator使用:(七)分布式Barrier
    Curator使用:(六)分布式计数器
    Curator使用:(五)分布式锁
    Curator使用:(四)Master选举
    Curator使用:(三)事件监听
  • 原文地址:https://www.cnblogs.com/hyc123/p/11454384.html
Copyright © 2011-2022 走看看