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....!")
    

      

     

  • 相关阅读:
    江西财经大学第一届程序设计竞赛 I 题 小P和小Q
    江西财经大学第一届程序设计竞赛 H题- 小P的数学问题
    C# 窗体
    数据库操作(对战游戏)
    数据库操作 (数据操作类)
    练习
    泛型集合
    数据库操作 (防注入攻击)
    数据库操作(增删改)
    DO.NET操作数据库
  • 原文地址:https://www.cnblogs.com/wakee/p/10921960.html
Copyright © 2011-2022 走看看