zoukankan      html  css  js  c++  java
  • 面向对象元类介绍 以及反射

    1 元类

    1 定义

    元类: 用于产生类的类 称之为元类

    元类翻译为:metaclass 只要看见它就应该想起来这是元类

     

    我们在定义元类时 尽量在类名后添加MetaClass 方便阅读

    一切皆对象

    类也是对象,可以把一个类当成普通对象来使用,比如存储到列表中,或者作为参数传给函数等等...

    对象是如何产生的? 通过类实例化产生的

    类对象 是由type实例化产生的

    class AClass:
        pass
    print(type(AClass)) # <class 'type'>
    

      

    2 类的三大组成部分

    1.类的名称 我是谁

    2.类的父类们 我从哪里来

    3.类的名称空间 我有什么

     

    我们可以手动调用type来实例化产生一个类 
    
    type(类名,父类元组,名称空间字典)  #返回一个新的类
    
    type(对象)  #将会返回这个对象的类型
    

    3 元类的运用

    class MyMetaClass(type):
        pass
    
    # 使用自定义元类
    class Person(metaclass=MyMetaClass):
        pass
    

      

     

    4 元类中的__init__运用

    实例化对象时会自动执行类中的`__init__`方法, 类也是对象 ,在实例化类对象时会自动执元类中的`__init__`方法
    
    并且传入类的三个必要参数,类的名字,父类们,名称空间
    
    当然会自动传入类对象本身作为第一个参数  
    

     

    案例:案例: 限制类名必须首字母大写 控制类中方法名必须全部小写

     
    class MyMetaClass(type):
        def __init__(self,class_name,bases,name_dict):
    
            super().__init__(class_name,bases,name_dict)  # 子类重用父类中的方法
            # 类名必须首字母大写  否则直接抛出异常
            if not class_name.istitle():
                print("类名必须大写 傻x!")
                raise Exception
    
            # 控制类中方法名必须全部小写
            for k in name_dict:
                if str(type(name_dict[k])) == "<class 'function'>":
                    if not k.islower():
                        raise Exception
        pass
    
    
    
    # 会自动调用其元类中的 __init__ 方法传入 类对象本身 类名称 父类们  名称空间
    class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{})
        NAME = 10
        def say(self):
            print("SAY")
        pass
    
    
    # 解释 class Student() 类 如果类名首字母不是大写就会报错   如果方法不是小写就会报错
    

     

    5 元类中的__new__方法

     

    元类中的new方法会在创建类对象时执行,并且先于init方法

    作用是创建一个类对象

    class A(metaclass=MyMetaClass):

    pass

    1.执行MyMetaClass的__new__方法 拿到一个类对象

    2.执行MyMetaClass的__init__ 方法 传入类对象以及其他的属性 ,进行初始化

     

    注意:如果覆盖了__new__ 一定也要调用type中的__new__并返回执行结果

    使用new方法也可以完成定制类的工作 和init有什么区别?

    在调用init方法前类对象已经创建完成了

    所以如果对性能要求高的话 可以选在在new中完成定制 如果发现有问题,就不用创建类对象了

     

    需求: 要求每个类必须包含__doc__属性

    class DocMeatClass(type):
    
        def __init__(self,class_name,bases,name_dict):
            super().__init__(class_name,bases,name_dict)
            # if not("__doc__" in name_dict and name_dict["__doc__"]):
            #     raise  Exception
            
            # 或者如下
            if not self.__doc__:
                raise Exception
    
    class Person(metaclass=DocMeatClass):
        """"""
        pass
    

      

    # 需求: 要求每个类必须包含__doc__属性   __doc__ 用于访问一个对象的注释信息
    
    
    # 你要控制类的创建  那就自定义元类 覆盖__init__
    class DocMeatClass(type):
    
        def __init__(self,class_name,bases,name_dict):
            super().__init__(class_name,bases,name_dict)
            # if not("__doc__" in name_dict and name_dict["__doc__"]):
            #     raise  Exception
            if not self.__doc__:
                raise Exception
    
    class Person(metaclass=DocMeatClass):
        pass
    

      

     

    6 元类中的__call__方法(重点)

    元类中的 call方法会在调用类时执行,
    
    可以用于控制对象的创建过程
    

      

    class MyMeta(type):
    
        # 获得某个类的实例
        def __call__(self, *args, **kwargs):
            print("call")
            # return super().__call__(*args,**kwargs)
            new_args = []
            for i in args:
                if isinstance(i,str):
                    new_args.append(i.upper())
                else:
                    new_args.append(i)
            return super().__call__(*new_args,**kwargs)
    
    
    
    # 注意注意注意:  __new__  __init__ 是创建类对象时还会执行
    # __call__ 类对象要产生实例时执行
    
    class Student(metaclass=MyMeta):
        def __init__(self,name,gender,age):
            self.name = name
            self.gender = gender
            self.age = age
    
    s = Student("jack","woman",18)
    print(s.age)
    print(s.gender)
    
    
    class Person(metaclass=MyMeta):
        def __init__(self,name,gender):
            self.name = name
            self.gender = gender
    
    p = Person("rose","man")
    print(p.name)
    

     

    总结:当你要定制类时,就自定义元类并覆盖init方法

     

    7 元类实现单例模式

     

    什么是单例:

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

    单例的好处:

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

    案例:

    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
    

        

    2 反射

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

     

    英文中叫反省 (自省)

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

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

    涉及到的方法:

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

      

     

     

  • 相关阅读:
    uip UDPclient模式通信移植,p本地ort可以是无规
    正则表达式摘要
    Regular expression
    正则-合乎规则
    通配符-通配
    正则表达式总结
    判断大盘筑顶的方法
    筑顶和下跌规律
    股票的筑顶危险信号
    股票筑顶的基本特征
  • 原文地址:https://www.cnblogs.com/wakee/p/10891757.html
Copyright © 2011-2022 走看看