zoukankan      html  css  js  c++  java
  • 贰拾叁

    一、元类

    ​ 在python中一切皆对象,所以类也是一个对象,对象是由类实例化产生的,所以类也可以实例化产生。那么实例化产生类的类就是元类。

    class B
    	def __init__(self,v)
    print(type(B))
    
    <class 'type'>
    

    ​ 使用print(type(类))的方法可以找到类的类。

    ​ type为python内置元类,所有的类都是由type实例化产生的。

    二、class底层原理分析

    ​ 平时使用class + 类名的方式将类构造出来,但实际上这些类是由元类实例化产生的。type为python内置元类,类是由type实例化产生,并且传入一堆参数。

    ​ type是使用类的内置__init__方法产生类的。

        # 类的源码
        def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
            """
            type(object_or_name, bases, dict)
            type(object) -> the object's type
            type(name, bases, dict) -> a new type
            # (copied from class doc)
            """
            pass
    

    ​ 元类通过object_or_name, bases, dict(类名:字符串,父类,名称空间:字典)的方式产生类,可以代替class关键字的方式。

    #通过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)
    

    三、通过元类控制类的产生

    ​ 通过控制类名,控制类的继承父类,控制类的名称空间的方法自定义元类,由此可以控制类的产生。

    ​ 自定义元类,都要继承type元类。

    class A(type):
    
    class B(metaclass=  A):
    

    ​ metaclass= A指定类B的元类为A。

    ​ 练习:自定义元类,控制类产生,类的名称空间必须要有name字段才能创建成功,否则失败。

    lass Mymeta(type):
        def __init__(self,name):
            if not 'name' in name:
                raise   TypeError('没有name字段')
    
    class Aname(object,metaclass=Mymeta):
        def __init__(self,name):
            self.name = name
    

    四、通过元类控制类的调用

    ​ 通过元类控制类的调用实际上是在控制对象的产生。

    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)
    

    ​ 类的调用过程是先触发元类的__call__ ,再触发类的init方法。

    ​ 练习:定义一个元类,定义一个类继承字典,使其具备点取值和赋值功能,通过元类控制对象的产生,把所有属性放在attr字典中,属性全删除。

    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            obj = self.__new__(self)
            obj.__init__(*args, **kwargs)
            dic = {}
            dict.update(obj.__dict__)
            attr = {'attr':dic}
            obj.__dict__.clear()
            obj.__dict__.update(attr)
            
    
    class Test(dict,metaclass=Mymeta):
        def __init__(self,**kwargs):
            self.__dict__.update(kwargs)
        def __getattr__(self, item):
            return self.__dict__['attr'][item]
        def __setattr__(self, key, value):
            self.__dict__['attr'][key] = value
            t = Test(name='lqz', age=18)
    print(t.__dict__)
    print(t.name)
    print(t.age)
    t.male = 'nan'
    print(t.male)
    print(t.__dict__)
    

    五、有元类后属性查找顺序

    ​ 类的属性查找顺序:先从类本身中找--->mro继承关系去父类中找---->去自己定义的元类中找--->type中--->报错

    ​ 对象的属性查找顺序:先从对象自身找--->类中找--->mro继承关系去父类中找--->报错

    5f192fd059540a603a133d3ff0b0ca0

  • 相关阅读:
    innodb临键锁锁定范围
    详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)
    解决Jenkins邮件配置问题
    解决import模块后提示无此模块的问题
    【转】Linux下cp: omitting directory `XXX'问题解决
    Python之异常处理(执行python文件时传入参数)
    Python之发邮件
    Python之递归
    Python之参数类型、变量
    linux sed命令详解
  • 原文地址:https://www.cnblogs.com/tangceng/p/11455813.html
Copyright © 2011-2022 走看看