zoukankan      html  css  js  c++  java
  • 元类

    元类的介绍

    产生类的类称之为元类,默认所以用class定义的类,他们的元类是type

    exec的使用:

    exec:三个参数
    参数一:字符串形式的命令
    参数二:全局作用域(字典形式),如果不指定,默认为globals()
    参数三:局部作用域(字典形式),如果不指定,默认为locals()

    例子:

    #可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
    g = {
        'x':1,
        'y':2
    }
    l = {}
    exec('''
    global x,z
    x = 200
    
    m = 400
    ''',g,l
    )
    print(g,l)
    '''
    输出结果:
    {'x': 200, 'y': 2, '....}
    {'m': 400}
    '''

    python中一切皆对象,类也是对象

    满足四个条件的就是对象:

    1、都可以被引用,x=obj
    2、都可以当作函数的参数传入
    3、都可以当作函数的返回值
    4、都可以当作容器类的元素,l=[func,time,obj,1]

    查看类的方法:

    class Foo:
        pass
    
    f1 = Foo()
    print(type(f1))
    print(type(Foo))
    '''
    输出结果:
    <class '__main__.Foo'> # 可以看出对象由Foo类创建
    <class 'type'># type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
    '''

    元类的创建方法:

    一、使用关键字class来进行创建

    class Zhugeliang:
        camp = 'red'
        def __init__(self,nickname,life_value,aggresivity):
            self.nickname = nickname
            self.life_value = life_value
            self.aggresivity = aggresivity

    二、就是手动模拟class创建类的过程):将创建类的步骤拆分开,手动去创建

    #手动创建类
    '''
    #定义类的三要素:
    类名
    类的基类
    类的名称空间
    '''
    #类名
    class_name = 'China'
    #类的基类
    class_base = (object,)
    #类的名称空间
    class_boy = '''
    country='China'
    
    def __init__(self,namem,age):
        self.name=namem
        self.age=age
    
    def talk(self):
        print('%s is talking' %self.name)
    '''
    '''步骤一(先处理类体->名称空间):类体定义的名字都会存放于类的名称空间中(一个局部的名称空间),我们可以事先定义一个空字典,然后用exec去执行类体的代码(exec产生名称空间的过程与真正的class过程类似,只是后者会将__开头的属性变形),生成类的局部名称空间,即填充字典
    '''
    class_dic = {}
    exec(class_boy,globals(),class_dic)
    #print(class_dic)
    #步骤二:调用元类type(也可以自定义)来产生类Chinense
    Chinese = type(class_name,class_base,class_dic)
    #print(Chinese)
    Chinese1 = Chinese('egon',18)
    #实例化type得到对象Chinese,即我们用class定义的类Chinese
    print(Chinese1.__dict__)
    '''
    输出结果:
    {'name': 'egon', 'age': 18}
    '''

    type 接收三个参数:

    • 第 1 个参数是字符串 ‘Foo’,表示类名
    • 第 2 个参数是元组 (object, ),表示所有的父类
    • 第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
      补充:若Foo类有继承,即class Foo(Bar):.... 则等同于type('Foo',(Bar,),{})

    自定义元类控制类的行为

    import re
    #自定义元类来控制首字母必须大写与必须加上注释
    class Mymeta(type):
        '''
        定义自己的元类
        '''
        def __init__(self,class_name,class_base,class_dic):
            num = re.search("^[A-Z]w+",class_name)
            if not num:
                raise TypeError('首字母必须大写')
            if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
                raise  TypeError('必须加上注释')
             super(Mymeta,self).__init__(class_name,class_base,class_dic)
    class Chinese(object,metaclass=Mymeta):
        '''
        自己的元类
        '''
        country='China'
        def __init__(self,namem,age):
            self.name=namem
            self.age=age
    
        def talk(self):
            print('%s is talking' %self.name)
    
    f = Chinese('egno',18)

    自定义元类来控制类的实例化

    #单例模式
    #方法一:
    # class  Msql:
    #     __instance = None
    #     def __init__(self):
    #         self.host = '127.0.0.1'
    #         self.port = 3038
    #
    #     @classmethod
    #     def singleton(cls):
    #         if not cls.__instance:
    #             obj = cls()
    #             cls.__instance = obj
    #         return cls.__instance
    #
    #     def connt(self):
    #         pass
    #
    # m1 = Msql.singleton()
    # m2 = Msql.singleton()
    # m3 = Msql.singleton()
    # print(m1 is m2 is m3)
    
    #方法二:
    import re
    class Mymeta(type):
        '''
        定义自己的元类
        '''
        def __init__(self,class_name,class_base,class_dic):
            num = re.search("^[A-Z]w+",class_name)
            if not num:
                raise TypeError('首字母必须大写')
            if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
                raise  TypeError('必须加上注释')
    
            super(Mymeta,self).__init__(class_name,class_base,class_dic)
            self.__intstance = None
    
        def __call__(self, *args, **kwargs): #实例化的时候就会触发这个方法
            if not self.__intstance:
                # obj = object.__new__(self) # 产生对象
                # self.__init__(obj) # 初始化对象
                # self.__intstance = obj
                self.__intstance = super.__call__(*args,**kwargs)#合并成一步
            return self.__intstance
    
    
    class  Msql(object,metaclass=Mymeta):
        '''
        控制实例化
        '''
        def __init__(self):
            self.host = '127.0.0.1'
            self.port = 3038
        def connt(self):
            pass
    
    m1 = Msql()
    m2 = Msql()
    print(id(m1))
    print(id(m2))
    print(m1 is m2)

    六 练习题

    练习一:在元类中控制把自定义类的数据属性都变成大写

    class Mymeta(type):
        '''
        定义自己的元类
        '''
        def __new__(cls,name,base,attrs):
            update_dic = {}
            for i,v in attrs.items():
                if not callable(v) and not i.startswith('__'):
                    update_dic[i.upper()] = v
                else:
                    update_dic[i] = v
            return type.__new__(cls,name,base,update_dic)
    
    class China(object,metaclass=Mymeta):
        country = 'China'
        tag = 'Legend of the Dragon'
        def walk(self):
            print('%s is walk'%self.name)
    
    print(China.__dict__)

    练习二:在元类中控制自定义的类无需init方法

    1.元类帮其完成创建对象,以及初始化操作;
      2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
      3.key作为用户自定义类产生对象的属性,且所有属性变成大写

    class Mymeta(type):
        '''
        定义自己的元类
        '''
        def __new__(cls,name,base,attrs):
            update_dic = {}
            for i,v in attrs.items():
                if not callable(v) and not i.startswith('__'):
                    update_dic[i.upper()] = v
                else:
                    update_dic[i] = v
            return type.__new__(cls,name,base,update_dic)
        def  __call__(self, *args, **kwargs):
            if args: #如果传入的值是元组就会报错
                raise  TypeError('must use keyword argument')
            obj = self.__new__(self) #产生对象
            for i,v in kwargs.items(): #循环传入的kwargs值
                obj.__dict__[i.upper()] = v
            return obj
    
    class China(object,metaclass=Mymeta):
        country = 'China'
        tag = 'Legend of the Dragon'
        def walk(self):
            print('%s is walk'%self.name)
    
    f = China(country='中国',name='egon',age=18)
    print(f.__dict__)

    <wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

  • 相关阅读:
    分布式文件系统
    分布式文件系统
    ASP.NET MVC 使用 FluentScheduler 定时器计划任务
    从零开始学 Java
    从零开始学 Java
    从零开始学 Java
    从零开始学 Java
    从零开始学 Java
    从零开始学 Java
    从零开始学 Java
  • 原文地址:https://www.cnblogs.com/yjiu1990/p/9144534.html
Copyright © 2011-2022 走看看