zoukankan      html  css  js  c++  java
  • 元类

    什么是元类

    1.在Python中一切皆对象,类也是一个对象,实例对象由类创建出来的,类是由元类创建出来的。简而言之,用来创建类的类就叫元类(metaclass)。

    2.函数type其实就是一个元类,type就是Python在背后用来创建所有类的元类。(type是内置的一个元类,所有的类都是由type实例化得到)

    class Person:  #生成一个简单的类
        def __init__(self, name):
            self.name = name
        def score(self):
            print('haha')
            
    p = Person('kang')
    
    a = Person
    p1 = a('kang')
    print(p1.name)
    # 打印结果为 kang
    
    #如何找元类
    print(type(p))
    <class '__main__.Person'> #这里查看的是p的数据类型
    #type类是产生所有类的元类
    print(type(Person))
    print(type(dict))
    print(type(list))
    #查看类的数据类型,以下类型均为type
    <class 'type'>
    <class 'type'>
    <class 'type'>
    

    class底层原理

    #class 类名  会把类构造出来
    #实际上是: 元类实例化产生类 这个对象
    #类实例化产生对象, 一定是:  类名()
    #比如person类, 是由type实例化产生的, 传入一堆参数
    # type() 就是调用类的__init__方法
    #手动实现
    #1. type()
    #type(object_name, bases, dict)
    #object_name:类的名字,是个字符串
    #bases:是它的所有父类,基类
    #dict: 名称空间,是一个字典
    
    #通过type来直接产生类, 而不是用class关键字
    l = {}
    
    exec('''
    school='oldboy'
    def __init__(self,name):
        self.name=name
    def score(self):
        print('分数是100')
    ''',{},l) #这里的{}表示全局名称空间, l表示局部名称空间
    Person = type('Person, (object,), l')  #按照上面的格式传值,就能用type来直接产生类
    #这就实现了通过type直接来产生Person类
    #class 底层就是调用type来实例化产生类
    
    #exec()  eval()的区别
    #通过exec可以执行动态Python代码,
    #而Python中的eval函数可以计算Python表达式,并返回结果;
    #(exec不返回结果,print(eval("…"))打印None);
    
    

    自定义元类控制类的产生

    自定义元类;来控制类的产生:可以控制类名,可以控制类的继承父类,控制类的名称空间
    #自定义元类必须继承type, 写一个类继承type 这种类就是元类
    class Mymate(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') #判断开头是否是'sb'
             #raise Exception('类名没有以sb开头') 抛错
            #练习二: 类必须加注释
            print(self.__dcit__['__doc__'])
    #metaclass = Mymeta 指定这个类生成的时候, 用自己写的Mymeta这个元类
    
    class Person(object, metaclass = Mymeta):
        '''
        注释
        '''
        school = 'oldboy'
        def __init__(self, name):
            self,name = name
        def score(self):
            print('40分')
         
    # 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')
    
            
            
    

    自定义元类控制类的执行过程

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

    #__call__
    class Mymeta(type):
        def __call__(self, **args,**kwargs):
            print(self) #self是People
            print(args) #args = {'kang'}
            print(kwargs) #kwargs = {'age':18}
            
            #retuen 123
            # 1.先造出一个People的空对象, 申请内存空间
            # __new__ 方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。
            obj = self.__new__(self) #虽然和上面的同样是People, 但是People没有, 找到的__new是父类的
            #2. 为该空对象初始化独有的属性
            self.__init__(obj, *args, **kwargs)
            return obj
    # People = Mymeta() People()则会触发__call__
    
    calss People(object, metaclass=Mymeta):
        country = 'China'
        
        def __init__(self, name, age):
            self.name = name
            self.age = age
            
         def eat(self):
            print(f'{self.name} is eating')
            
            #再调用Mymeta的__call__的时候, 首先找到自己(如下函数)的, 自己的没有才会找父类的
            def __new__(cls, *args, **kwargs):
                # print(cls) # cls是People
                # cls.__new__(cls) #错误, 无限死循环, 自己找自己的, 会无限的递归下去
                obj = super(People, cls).__new__(cls) # 使用父类的, 则是去父类中找__new__
                return obj
            
            
        
        
    
    
    
    • 类的调用,即类实例化就是元类的调用过程,可以通过元类Mymeta的__call__方法控制
    • 分析:调用Pepole的目的
      1. 先造出一个People的空对象
      2. 为该对空对象初始化独有的属性
      3. 返回一个初始化好的对象

    属性查找

    查找顺序:

    1. 先对象层:OldoyTeacher->Foo->Bar->object

    2. 然后元类层:Mymeta->type

    3. 类的属性查找顺序:先从类本身中找--->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)
    
    
    
    

    作业

    class Mymeta(type):
        def __init__(self, name, bases, dic):
            doc = self.__dict__.get('name')
            if not doc:
                raise Exception('你的名称空间中没有name字段')
            print('存在name字段')
    
    class Person(object,metaclass=Mymeta):
    
        school='oldboy'
        def __init__(self,name):
             self.name=name
        def score(self):
            print('分数是100')
    
        def name(self):
            print('you')
    
    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            self.attr = kwargs
            obj = self.__new__(self,*args,**kwargs)
            return obj
    
    
    class Mydic(dict, metaclass=Mymeta):
        def __init__(self,**kwargs):
            super().__init__(self, **kwargs)
    
        def __getitem__(self, item):
            return self[item]
    
        def __setattr__(self, key, value):
            self[key] = value
    
    dic = Mydic(name='nick', age=18)
    print(dic.__dict__)
    print(dic.attr)
    
    
    
  • 相关阅读:
    tomcat 配置文件下载目录
    AeroSpike 资料
    NodeManager起不来
    添加Microsoft SQL JDBC driver 到 Maven
    广告投放网站集合
    eMarketer:DMP帮广告主搞定大数据处理问题
    HUE 忘记密码
    Git客户端图文详解如何安装配置GitHub操作流程攻略
    httprunner3.x 测试用例-teststeps-RunTestCase
    httprunner3.x 测试用例teststeps-RunRequest
  • 原文地址:https://www.cnblogs.com/kangwy/p/11461531.html
Copyright © 2011-2022 走看看