zoukankan      html  css  js  c++  java
  • 元类以及反射

    元类定义

    '''
    什么是元类: 就是产生类的类 简称为元类  metaclass
    用途:对类的产生设定一些规定,
    作用: 创建新的元类继承type,通过覆盖"__init__"完成对类的限制. 如例子对类名和方法的限制
    什么时候用 :  需要对类进行一些限制的时候
    '''

    type的两种用法  

    type 的两种意思:  一种是类型的  比如 print(isinstance('a', str))  二是类的元类
    type(对象) 就是对象的类型
    type(类名,父类们,名称空间)  产生的 就是一个新的类  名称空间实际上就是一个字典  用来存贮数据的
    3:类的组成部分  1)类名  2)父类们  3)名称空间
    

     

    type接收三个参数分别是:
    classname: 要创建的class 的名称
    object:要创建类的父类所组成的元组
    sttr_dict: 要创建类的属性
    type返回一个class,我们接收并赋值到一个变量上,现在这个变量就指向我们所创建的类,我们可以通过这个变量来使用类
    

      

    自定义元类

    class UpperAttrMetaClass(type):
        def __new__(cls,class_name,class_parents,class_attr, *args, **kwargs):
            print("__new__")
            class_attr['name'] = "jiao"
            return type.__new__(cls,class_name,class_parents,class_attr)
        def __init__(self,*args,**kwargs):
            print("__init__")
            super().__init__(*args, **kwargs)
            self.__cache = {}
        def __call__(self, *args, **kwargs):
            print("__call__")
            if args in self.__cache:
                return self.__cache[args]
            else:
                obj = super().__call__(*args)
                self.__cache[args] = obj
                return obj

    class A(metaclass=UpperAttrMetaClass):
        def __init__(self,name):
            self.name = name
            print("a.__init__")


    元类中__init__ __new__ __call__ 函数

    1)__init__在元类中的应用

     在实例化对象时会自动调用__init__方法,会将对象本身作为第一个参数传递过去
     因为类也是对象  在实例化类对象时也会自动调用__init__方法,会见类对象作为第一个参数传递进去,
     也会传递三个参数  分别是 类名称  父类们  名称空间
    __init__在元类中的作用: 创建新的元类继承type,通过覆盖"__init__"完成对类的限制.
    

      

    class A:
        def __init__(self,name):
            self.name= name
    a= A()#  实例化对象
    
    class MyMetaclass(type):
        def __init__(self,class_name,bases,name_dict):  # 
            '''
            自定义元类
            :param class_name: 类名称
            :param bases: 父类们
            :param name_dict: 名称空间
            '''
            pass
    class B(metaclass=MyMetaclass):  # 此时运行到class 就是实例化类对象B了
        pass
    # 案例   限制类名必须首字母大写   控制类中方法名必须全部小写
    # 分析:那么可以元类中限制类的创建条件
    # 因为类名和属性和方法都是存储到类中名称空间的 类名下对应下是属性和方法 那么可以通过操作名称空间进行限制
    
    class MyMetaclass(type):
        def __init__(self,class_name,bases,name_dict):
            # 元类的self代表的就是类对象
            super().__init__(class_name,bases,name_dict)
            # 对父类进行初始化
    
            # 对类名首字母进行限制 必须大写字母
            if not class_name.istitle():
                print('类名必须大写')
            # else:  这一行可不需要
                raise Exception # 否则就报异常
    
            # 取出类中的属性和方法
            for k in name_dict:
                if str(type(name_dict[k])) == "<class 'function'>": #  "<class 'function'>" 就是类的方法
                    if not k.islower():
                        print('方法首字母必须小写')
                        raise Exception
    
    
    
    
    class student(object,metaclass=MyMetaclass):  # 类名小写报错    提示 类名必须大写 根据上面元类的限制类名的方法
        NAME = 10
        def say_hai(self):
            print("============")
    
    # class Student(metaclass=MyMetaclass):  #  方法名大写报错  提示 方法名必须小写 
    #     name = 10
    #     def Say(self):
    #         print('111111111111111111111')


    元类中的__new__方法 

    __new__创建类对像的时候执行   先于__init__运行
    作用:创建类对象
    注意:如果覆盖了`__new__` 一定也要调用type中的`__new__`并返回执行结果
    __new__与__init__的区别 :
    1)先于__init__执行
    2)__new__是创建类对象的(指的是元类的对象) __init__是实例化类对象的

      

    class MyMetaclass(type):
        def __init__(self,class_name,bases,name_dict):
            pass
    
        def __new__(cls, *args, **kwargs):
            # pass
            # cls表示类自己  即MyMetaclass
            return type.__new__(cls,*args,**kwargs)
    
    
    class People(metaclass=MyMetaclass):
        pass
    print(People)
    # __new__作用是创建类的  必须要返回值 没有无法创建对象的 当把return type.__new__(cls,*args,**kwargs)注释掉
    # print(People) 的结果是None
    # 案例  要求每个类中必须含有__doc__属性  就是必须要有注释的意思
    
    class MyMetaclass(type):
        def __init__(self,class_name,bases,name_dict):
            super().__init__(class_name,bases,name_dict)
            # if not self.__doc__:
            #     raise Exception  # 两种方法都行
            # 或者
            if not('__doc__' in name_dict and name_dict['__doc__']):  #  __doc__在名称空间还里
                raise Exception
    
    # class A(metaclass=MyMetaclass):
    #     pass  # 无注释 报错
    
    class B(metaclass=MyMetaclass):  #有注释不报错
        '''
        
        '''

    元类中的__call__

    执行时机:在元类中,调用类时执行
    作用:控制对象的创建过程
    案例  用__call__来实现单例模式  单例模式就是仅有一个实例的意思
    

      

    class SingletonMetaClass(type):
        #创建类时会执init 在这为每个类设置一个obj属性 默认为None
        def __init__(self,a,b,c):
            super().__init__(a,b,c)
            self.obj = None
    
        # 当类要创建对象时会执行 该方法
        def __call__(self, *args, **kwargs):
             # 判断这个类 如果已经有实例了就 直接返回 从而实现单例
            if self.obj:
                return self.obj
    
            # 没有则创建新的实例并保存到类中
            obj = type.__call__(self,*args,**kwargs)
            self.obj = obj
            return obj  #  这是比较固定模式 记住以上三部分
    
    class People(metaclass=SingletonMetaClass):
        def __init__(self,name,age,gender):
            self.name=name
            self.age =age
            self.gender =gender
        def  say(self):
            print('my name is %s my aunt is 龙妈'% self.name)
    
    class Stu(metaclass=SingletonMetaClass):
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def say(self):
            print('my name is %s my aunt is 龙妈' % self.name)
    
    
    
    p1 = People('jeck',18,'man')
    print(p1)  #  地址都是一样的
    
    p2 = People('tom',22,'man')
    print(p2)  # 地址都是一样的
    # 案例  单例模式制作一个QQ播放器案例
    
    class MyMetaclass(type):
        def __init__(self,class_name,bases,name_dict):
            super().__init__(class_name,bases,name_dict)
            self.obj = None
    
        def __call__(self, *args, **kwargs):
            if self.obj:
                return self.obj
    
            obj = type.__call__(self,*args,**kwargs)
            self.obj = obj
            return obj
    
    class QQplayer(metaclass=MyMetaclass):
        def __init__(self,voice_value,repeat=None):  #  repeat  重复的意思
            self.voice_value =voice_value
            self.repeat = repeat
    
        def play(self,file_path):  # 播放功能
            if hasattr(self,'file_path'):  #
                self.stop()
            print('正在播放%s' % file_path)
            self.file_path = file_path
    
        def stop(self):  # 停止播放
            print('停止播放%s' % self.file_path)
    
    
    
    q1 = QQplayer(100,True)
    q1.play('多远多要在一起')
    
    q2 = QQplayer(80,True)
    q2.play('泡沫')
    # 正在播放多远多要在一起
    # 停止播放多远多要在一起
    # 正在播放泡沫
    
    
    # 1. hasattr(object, 'name')
    #
    #   判断object对象中是否存在name属性,当然对于python的对象而言,属性包含变量和方法;有则返回True,没有则返回False;
    # 需要注意的是name参数是string类型,所以不管是要判断变量还是方法,其名称都以字符串形式传参;getattr和setattr和delattr也同样;

     

    元类实现单例模式

    什么是单例:

    某个类如果只有一个实例对象,那么该类成为单例类

    单例的好处:

    当某个类的所有对象特征和行为完全一样时,避免重复创建对象,浪费资源

    案例:

    class SingletonMetaClass(type):
        #创建类时会执init 在这为每个类设置一个obj属性 默认为None
        def __init__(self,a,b,c):
            super().__init__(a,b,c)
            self.obj = None
        
        # 当类要创建对象时会执行 该方法
        def __call__(self, *args, **kwargs):
             # 判断这个类 如果已经有实例了就直接返回 从而实现单例
            if self.obj:
                return self.obj
    
            # 没有则创建新的实例并保存到类中
            obj = type.__call__(self,*args,**kwargs)
            self.obj = obj
            return obj
    

      

    反射

    反射就是通过字符串来操作对象属性

    英文中叫反省 (自省)

    面向对象中的反省 指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力;

    一个对象在设计初期,可能考虑不够周全后期需要删除或修改已经存在的属性, 和增加属性

    涉及到的方法:

    hasattr 判断是否存在某个属性
    
    getattr	获取某个属性的值
    
    setattr	新增或修改某个属性 
    
    delattr 删除某个属性
    

    案例:  

    class MY_CMD:
    
        def dir(self):
            os.system("dir")
    
        def ipconfig(self):
            os.system("ipconfig")
    
    cmd = MY_CMD()
    
    while True:
        name = input("请输入要执行的功能:")
        if hasattr(cmd,name):
            method = getattr(cmd,name)
            print(method)
            method()
        else:
            print("sorry this method is not exists....!")
    

      

     

  • 相关阅读:
    UVALive 6909 Kevin's Problem 数学排列组合
    UVALive 6908 Electric Bike dp
    UVALive 6907 Body Building tarjan
    UVALive 6906 Cluster Analysis 并查集
    八月微博
    hdu 5784 How Many Triangles 计算几何,平面有多少个锐角三角形
    hdu 5792 World is Exploding 树状数组
    hdu 5791 Two dp
    hdu 5787 K-wolf Number 数位dp
    hdu 5783 Divide the Sequence 贪心
  • 原文地址:https://www.cnblogs.com/wakee/p/10921960.html
Copyright © 2011-2022 走看看