zoukankan      html  css  js  c++  java
  • 反射

    反射

    一、什么是反射

    ​ 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

    ​ 反射被称为框架的基石,因为框架的设计者,不可能提前知道你的对象到底是怎么设计的,所以你提供给框架的对象 必须通过判断验证之后才能正常使用,判断验证就是反射要做的事情,当然通过__dict__也是可以实现的, 其实这些方法也就是对__dict__的操作进行了封装。

    ​ 反射其实就是对属性的增删改查,但是如果直接使用内置的__dict__来操作,语法繁琐,不好理解,另外一个最主要的问题是,如果对象不是我自己写的是另一方提供的,我就必须判断这个对象是否满足的要求,也就是是否我需要的属性和方法 。

    二、python中的反射

    • 反射是所有面向对象编程语言都具备的功能

    • python中通过以下四个函数来实现反射

      hasattr(object, name) # 判断对象是否拥有某个属性
      setattr(object,name,value) # 为对象增加新的属性
      getattr(object,name,default) # 从对象中获取某个属性
      delattr(object,name) # 从对象中删除某个属性
      

      参数object可以是任意对象,包括类

    三、为什么需要反射

    • 一个类在定义的时候,可能一些属性的设计并不是很完美,而后期需要作出修改,或是增加新属性时,使用反射的方式可以不需要修改源代码

    • 反射的另一个优势:可插拔设计(重点)

      不仅限于修改已有的属性,通过反(反省)也能够发现已经存在的属性,只要你给我一个对象我就能检查其拥有的属性,从而使用这些属性,而不需要提前了解这些对象,这大大提高了程序的扩展性

    四、如何使用

    • 案例一
    class FtpClient:
        'ftp客户端,但是还么有实现具体的功能'
        def __init__(self,addr):
            print('正在连接服务器[%s]' %addr)
            self.addr=addr
    
    f1=FtpClient('192.168.1.1')
    # 反射f1中的方法 如果存在就调用
    if hasattr(f1,'get'):
        func_get=getattr(f1,'get')
        func_get()
    else:
        print('---->不存在此方法')
        print('处理其他的逻辑')
    
    • 案例二:要实现一个用于处理用户的终端指令的小框架,框架就是已经实现了最基础的构架,就是所有项目都一样的部分

    import plugins
    
    # 框架已经实现的部分
    def run(plugin):
        while True:
            cmd = input("请输入指令:")
            if cmd == "exit":
                break
            # 因为无法确定框架使用者是否传入正确的对象所以需要使用反射来检测
            # 判断对象是否具备处理这个指令的方法
            if hasattr(plugin,cmd):
                # 取出对应方法方法
                func = getattr(plugin,cmd)
                func() # 执行方法处理指令
            else:
                print("该指令不受支持...")
        print("see you la la!")
    
    
    # 创建一个插件对象 调用框架来使用它
    # wincmd = plugins.WinCMD()
    # 框架之外的部分就有自定义对象来完成
    linux = plugins.LinuxCMD()
    run(linux)
    
    # 插件部分
    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 列出所有文件....")
    

    ​ 上述框架代码中,写死了必须使用某个类,这是个不合理的,因为无法提前知道对方的类在什么地方,以及类叫什么,所以我们应该为框架的使用者提供一个配置文件,要求对方将类的信息写入配置文件,然后框架自己去加载需要的模块。如此一来, 框架就与实现代码彻底解耦了,只剩下配置文件。

    import importlib
    import settings
    
    # 框架已经实现的部分
    def run(plugin):
        while True:
            cmd = input("请输入指令:")
            if cmd == "exit":
                break
            # 因为无法确定框架使用者是否传入正确的对象所以需要使用反射来检测
            # 判断对象是否具备处理这个指令的方法
            if hasattr(plugin,cmd):
                # 取出对应方法方法
                func = getattr(plugin,cmd)
                func() # 执行方法处理指令
            else:
                print("该指令不受支持...")
        print("see you la la!")
    
    
    # 创建一个插件对象 调用框架来使用它
    # wincmd = plugins.WinCMD()
    # 框架之外的部分就有自定义对象来完成
    
    # 框架 得根据配置文件拿到需要的类
    
    path = settings.CLASS_PATH
    # 从配置中单独拿出来 模块路径和 类名称
    module_path,class_name = path.rsplit(".",1)
    #拿到模块
    mk = importlib.import_module(module_path)
    # 拿到类
    cls = getattr(mk,class_name)
    # 实例化对象
    obj = cls()
    #调用框架
    run(obj)
    
  • 相关阅读:
    WPF 策略模式
    老陈 WPF
    老陈 ASP.NET封装
    小石头 封装
    典型用户故事
    整数的四则运算
    对git的认识
    如何学习计算机
    团队编程二——web应用之人事管理系统
    团队编程——web应用之人事管理系统
  • 原文地址:https://www.cnblogs.com/DcentMan/p/11307251.html
Copyright © 2011-2022 走看看