OOP之反射和元类

  • 反射(reflection)

  • 定义:指的是对象可以通过代码来增删改查其中的属性以及方法

  • 通过四个函数来实现这个功能,它们分别是hasattr()(),getattr()(),setattr()(),delattr()(

  • class Player:
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
        def playoff(self):
            print('他能在季后赛砍下30分')
    
    kobe = Player('kobe bryant',42,'male')
    
    print(hasattr(kobe,'name'))             # 判断kobe对象中有无'name'的属性或者方法
    print(getattr(kobe,'name'))             # 从kobe对象中取出name属性
    print(getattr(kobe,'career','DDD'))     # 如果对象中没有指定的属性,则返回最后一个参数即默认值可以是字符串也可以是布尔值
    
    getattr(kobe,'playoff')()               # 其中也可以从对象中取出方法加括号的方式调用
    
    setattr(kobe,'team','lakers')           # 在对象中添加属性,对象名,属性名,属性的值
    
    delattr(kobe,'team')                    # 删除对象中的team属性
    print(kobe.team)                        # 报错AttributeError: 'Player' object has no attribute 'team'
  • 为什么要引入反射概念

  • 一方面是不用通过__dict__方法查找对象中的属性以及方法名,极大地简化了操作属性的步骤和程序
  • 另一方面也是最重要的一点是,如果这个对象不是自己写的话,,我就必须判断这个对象是否满足的要求,也就是否符合我需要的属性和方法
  • 框架代码

  • from lib import settings        # 加载输出文件
    import importlib                # 导入模块的模块文件
    
    def run(insert_thing):          # 我要知道这个对象是插件中的哪个类的对象
        while True:
            cmd = input('请输入您想要执行的功能>>>:')
            if cmd == 'exit':
                print('退出程序')
                break
            if hasattr(insert_thing,cmd):
                func = getattr(insert_thing,cmd)
                func()
            else:
                print('您输入的功能不存在')
    
    # 将路径导出
    path = settings.CLASS_PATH
    # 拿出插件模块名称和类名称
    module_name, class_name = path.rsplit('.',1)
    
    # 导入插件模块
    module = importlib.import_module(module_name)
    # 取出类名称
    cls = getattr(module,class_name)
    print(cls)
    obj = cls()
    
    # 运行
    run(obj)
  • 插件模块代码

  • class WinCMD:
    
        def cd(self):
            print("wincmd 切换目录....")
    
        def delete(self):
            print("wincmd 要不要删库跑路?")
    
        def dir(self):
            print("wincmd 列出所有文件....")
    
    class LinuxCMD:
    
        def cd(self):
            print("Linuxcmd 切换目录....")
    
        def rm(self):
            print("Linuxcmd 要不要删库跑路?")
    
        def ls(self):
            print("Linuxcmd 列出所有文件....")


    CLASS_PATH = 'inserthings.WinCMD' 这个是配置文件中的代码

     

  • 元类(metaclass)

  • 定义:创建类的类,其不光能定义对象的行为还能够定义类的行为。说白了类就是元类的实例化,任何类都是type类的实例化。

  • class Person:
        pass
    p = Person()
    
    print(type(p))              # <class '__main__.Person'>
    print(type(Person))         # <class 'type'>
    
    # Person类是通过type类实例化产生的

     

  • 似乎元类和继承有着相似的地方,但是它们是完全不同的,元类是类的实例化,而继承则是类与类之间的联系,子类可以使用父类中的属性和方法,元类则是产生与被产生(类与对象)的关系,用来限制类的创建

  • 如何控制类对象的创建

  • __init__ 方法(创建类之后的调用)

  • """
    只要继承了type类,那么该类就是一个元类
    """
    
    class Type2(type):
        def __init__(self,cls_name,base,dict):
            super().__init__(cls_name,base,dict)
            print(cls_name,base,dict)
            if not cls_name.istitle():
                print('你的类的首字母没有大写')
    
    
    class Instance(metaclass = Type2):          # 为实例化的一个类指定了元类
        pass
    class instance1(metaclass = Type2):         # 输出你的类的首字母没有大写,起到了限制类的名字命名规范的效果
        pass

     

  • 控制类实例化对象的创建 __call__方法

  • 当你调用类对象时会自动珍惜元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数,覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建并返回其返回值。

  • class Upper(type):
        def __call__(self,*args,**kwargs):
            new_args = []   
            for item in args:
                new_args.append(item.upper())
            print(new_args)                                 # ['KOBE', 'MALE']
            return super().__call__(*new_args,**kwargs)
    
    
    class Student(metaclass = Upper):
        def __init__(self,name,gender):
            self.name = name
            self.gender = gender
    
    stu1 = Student('kobe','male')
    print(stu1.name)                                        # 返回KOBE

     

  • 控制类创建的__new__方法(创建类的时候实例化方法)

  • 当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作 注意:如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是,对应的类对象

  • class Meta(type):
    
        def __new__(cls, *args, **kwargs):
            print(cls) # 元类自己
            print(args) # 创建类需要的几个参数  类名,基类,名称空间
            print(kwargs) #空的 
            print("new run")
            # return super().__new__(cls,*args,**kwargs)
            obj = type.__new__(cls,*args,**kwargs)
            return obj
        def __init__(self,a,b,c):
            super().__init__(a,b,c)
            print("init run")
    class A(metaclass=Meta):
        pass
    print(A)

     

  • 单例设计模式

  • # 单例n元类
    class Single(type):
        def __call__(self, *args, **kwargs):
            if hasattr(self,"obj"): #判断是否存在已经有的对象
                return getattr(self,"obj") # 有就返回
    
            obj = super().__call__(*args,**kwargs) # 没有则创建
            print("new 了")
            self.obj = obj # 并存入类中
            return obj
    
    
    class Student(metaclass=Single):
        def __init__(self,name):
            self.name = name

     

 

 

 

posted @ 2019-07-30 22:28  ITchemist  阅读(160)  评论(0编辑  收藏  举报