• day 29 元类


    ---恢复内容开始---

    一、元类的介绍
    元类:在python里,一切皆对象。所有自定义的类本身也是元类的对象,即所有自定义的类本质上也是由元类实例化出来的。
    
    class关键字创建自定义类的底层的工作原理(分为四步)
    1、先拿到类名
    2、再拿到类的基类们 (object,)
    3、接着拿到类的名称空间
    4、调用元类实例化得到自定义的类
    
    
    通过class关键字创建一个类
    
    class text:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
    text1=text('jun',18)
    print(type(text))    #<class 'type'>
    
    不依赖class自定义一个类:
    #1、拿到类名
    class_name='text'
    #2、拿到类的基类
    class_bases=(object,)
    #3、拿到类的名称空间
    class_dic={}
    
    补充exec的用法:
    class_body='''
    class text:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    '''
    exec(class_body,{},class_dic)   class_body是局部变量,{}是全局变量   class_dic是名称空间
    print(class_dic)  #  {'text': <class 'text'>}
    
    #4、调用type得到自定义的类
    temp=type(class_name,class_bases,class_dic)
    print(temp)     #<class '__main__.text'>
               
    
    二、自定义元类埃控制类的产生
    
    类的产生:
    1、文档必须使用驼峰体
    2、类名中必须有文档注释,且文档注释不能为空
    #上述为默契,也可以通过代码来达到这些要求
    
    class Mymeta(type):#但凡继承type的类才能称为自定义的元类,否则就只是一个普通的类
    
        def __init__(self,class_name,class_bases,class_dic):
            if class_name.islower():
                raise TypeError('类名必须使用驼峰体')
    
            doc = class_dic.get('__doc__')
            if doc is None or len(doc) == 0 or len(doc.strip('
     ')) == 0:
                raise TypeError('类体中必须有文档注释,且文档注释不能为空')
    
            print(self)   #<class '__main__.Oldboy'>
            print(class_name)   #Oldboy
            print(class_bases)     #(<class 'object'>,)
            print(class_dic)  #{'__module__': '__main__', '__qualname__': 'Oldboy', '__init__': <function oldboy.__init__ at 0x00000000021A1730>}
    
    class Oldboy(object,metaclass=Mymeta): #oldboy=Mymeta('oldboy',(object,),{})
        '''
        必须存在文档注释
        '''
    
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
    print(Oldboy)  #<class '__main__.Oldboy'>
    

      

    三、自定义元类控制类的调用过程
    
    class Mymeta(type):
    
        pass
    
    class text(object):
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
        def __call__(self, *args, **kwargs):
            print(self)
            print(args)
            print(kwargs)
    
    temp=text('jun',18,'male')
    
    temp(1,2,a=1,b=2) #==__call__(temp,(1,2),{'a':1,'b':2})
    #对象的调用
    
    #对象之所以可以调用,是因为对象的类中有一个函数 __call__
    #推导:如果一切皆对象,那么text也是一个对象,该对象之所以可以调用,
    #是因为该对象的类中也定义了__call__
    
    
    class Mymeta(type):
        def __call__(self, *args, **kwargs):  #此处的self=text这个类
            # 1、先产生一个空对象
            obj=self.__new__(self)  #obj是text这个类的对象
     # 2、执行__init__方法,完成对象的初始化属性操作
    self.__init__(obj,*args,**kwargs)
    print(obj.__dict__) #{'name': 'jun', 'age': 18, 'sex': 'male'} 查找对象的字典
    obj.__dict__={('_%s__%s'%(self.__name__,k)):v for k,v in obj.__dict__.items() }
    #这一步可以做到私有化属性
    print(obj.__dict__) #{'_text__name': 'jun', '_text__age': 18, '_text__sex': 'male'}

    # 3、返回初始化好的那个对象
    return obj

    class text(object,metaclass=Mymeta):
    def __init__(self, name, age, sex):
    self.name = name
    self.age = age
    self.sex = sex

    temp=text('jun',18,'male') #会触发元类中的__call__函数
    print(temp) #<__main__.text object at 0x0000000001DD9208>
    #实例化
    #1、先产生一个空对象
    #2、执行__init__方法,完成对象的初始化属性操作
    #3、返回初始化好的那个对象
    
    
    补充:exec,eval
    # eval内置函数的使用场景:
    #   1.执行字符串会得到相应的执行结果
    #   2.一般用于类型转化,得到dict、list、tuple等
    
    dic_str = "{'a': 1, 'b': 2, 'c': 3}"
    res = (eval('dic_str'))  # 得到原先的结果
    res1 = (eval(dic_str))  # 得到字符串里面的类型
    print(type(res), type(res1))  # <class 'str'> <class 'dict'>
    
    list_str = "[1, 2, 3, 4, 5]"
    print(list_str, type(list_str))  # [1, 2, 3, 4, 5] <class 'str'>
    print(type(eval(list_str)))  # <class 'list'>
    
    with open('2.txt', 'r', encoding='utf-8') as rf:
        data_str = rf.read()
        print(data_str, type(data_str))  # [1, 2, 3, 4, 5] <class 'str'>
    
        import json  # 文件里字典里的key的引号必须为双引号
    
        res = json.loads(data_str)  # 字符串转化为其他格式
        print(res, type(res))  # [1, 2, 3, 4, 5] <class 'list'>
    
    data_str = "{'a': 1, 'b': 2, 'c': 3}"  # 可以不考虑引号的种类,直接转换
    res = eval(data_str)
    print(res, type(res))  # {'a': 1, 'b': 2, 'c': 3} <class 'dict'>
    
    
    # exec应用场景
    #   1.执行字符串没有执行结果(没有返回值)
    #   2.将执行的字符串中产生的名字形成对应的局部名称空间
    
    
    s = '''
    my_a = 10
    my_b = 20
    def __init__(self):
        pass
    @classmethod
    def print_msg(msg):
        print(msg)
    '''
    l_dic = {}
    exec(s, {}, l_dic)          #s是局部变量,{}是全局变量,l_dic名称空间
    print(l_dic)
    print(l_dic.items())  #{'name': 'Bob', 'age': 20}
    

      

  • 相关阅读:
    链接程序和库
    setjmp.h 文件解析与使用
    程序中的.dll .lib .def 和 .exp文件
    GDB开发测试相关
    gdb调试方法
    gdb代码分析
    ln对目录下所有文件做软链接
    python pexecpt模块 实现自动交互
    vscode中less自动输出为wxss或者css
    cmake
  • 原文地址:https://www.cnblogs.com/changwenjun-666/p/10785549.html
Copyright © 2020-2023  润新知