• 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

     

  • 相关阅读:
    如何去掉流氓网站http://www.2345.com/?177
    『ExtJS』01 004. ExtJS 4 确定函数的作用域
    『Java』Servlet 最简教程
    『Java』最简教程
    『ExtJS』01 002. ExtJS 4 类的继承
    『ExtJS』01 003. ExtJS 4 类的混合
    『ExtJS』01 006. ExtJS 4 组件的别名
    『ExtJS』01 007. ExtJS 4 查找组件
    『ExtJS』01 005. ExtJS 4 类的‘Import’
    『ExtJS』01 001. ExtJS 4 类的定义
  • 原文地址:https://www.cnblogs.com/ITchemist/p/11273223.html
Copyright © 2020-2023  润新知