• Python全栈开发记录_第十篇(反射及选课系统练习)


      反射机制:反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块中寻找指定函数,对其进行操作。也就是利用字符串的形式去对象(模块)中操作(查找or获取or删除or添加)成员,一种基于字符串的事件驱动。

    上面对反射的解释估计没听懂吧,这样我们一步一步来,看为啥我们会使用到反射机制以及如何使用。

    我们在访问网站的时候,比如商城的时候,我们访问不同页面是不是url后缀会不同,如果点击首页,则会跳转至xxx/index,下图所示:

    # func.py文件内容
    def index():
        print("首页")
    
    
    def login():
        print("登录页面")
    
    # test.py文件内容 import func def run(): input_str = input(">>>")
      # 根据不同的url,执行不同的函数,获得不同的页面
    if input_str == "index": func.index() elif input_str == "login": func.login() else: print("404") if __name__ == "__main__": run()

    上面的写法是比较笨拙的一种写法, 如果func.py内有上千个函数呢?因此这就引用到了反射的概念,将代码修改,如下:

    import func
    
    
    def run():
        input_str = input(">>>")
        # 说明:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的),有则返回true,否则返回false
        if hasattr(func, input_str):
            # 从object(func模块)中取成员(input_str函数)
            f = getattr(func, input_str)
            f()
        else:
            print("404")
    
    
    if __name__ == "__main__":
        run()

      python的四个重要内置函数:getattrhasattrdelattrsetattr较为全面的实现了基于字符串的反射机制。他们都是对内存内的模块进行操作,并不会对源文件进行修改。

    r = hasattr(commons,xxx)判断某个函数或者变量是否存在
    print(r)  
    
    setattr(commons,'age',18)  给commons模块增加一个全局变量age = 18,创建成功返回none
    
    setattr(config,'age',lambda  a:a+1)  //给模块添加一个函数
    
    delattr(commons,'age')//删除模块中某个变量或者函数

    但是我们问题又来了,上面的例子是在某个特定的目录结构下才能正常实现的,也就是func和test模块在同一目录下,并且所有的页面处理函数都在test模块内。但在现实使用环境中,页面处理函数往往被分类放置在不同目录的不同模块中,难道我们要在test模块里写上一大堆的import 语句逐个导入func还有其它模块吗?要是有上千个这种模块呢?如下图:

      刚才我们分析完了基于字符串的反射,实现了动态的函数调用功能,我们不禁会想那么能不能动态导入模块呢?这完全是可以的!python提供了一个特殊的方法:__import__(字符串参数)。通过它,我们就可以实现类似的反射功能。__import__()方法会根据参数,动态的导入同名的模块。

    def run():
        input_str = input(">>>")  # 输入func1/index1
        m, f = input_str.split('/')
        # 导入了m这个变量保存的字符串同名的模块,并将它赋值给obj变量
        obj = __import__(m)
        if hasattr(obj, f):
            fun = getattr(obj, f)
            fun()
        else:
            print("404")
    
    
    
    if __name__ == "__main__":
        run()

    不过如果目录结构变成了这样呢?我们要导入other下面的呢?

    def run():
        input_str = input(">>>")  # func/index
        m, f = input_str.split('/')
        # 导入了m这个变量保存的字符串同名的模块,并将它赋值给obj变量
        obj = __import__("other."+m, fromlist=True) # 如果不加上fromlist=True,只会导入other目录
        if hasattr(obj, f):
            fun = getattr(obj, f)
            fun()
        else:
            print("404")
    
    
    if __name__ == "__main__":
        run()

    至此,动态导入模块的问题基本都解决了,只剩下最后一个,那就是万一用户输入错误的模块名呢?比如用户输入了somemodules/find,由于实际上不存在somemodules这个模块,必然会报错!那有没有类似上面hasattr内置函数这么个功能呢?答案是没有!碰到这种,你只能通过异常处理来解决。

    练习:选课系统

    一、选课系统(面向对象作业)
    
    角色:学校、学员、课程、讲师
    要求:
    1. 创建北京、上海 2 所学校
    2. 创建linux , python , go 3个课程 , linuxpy 在北京开, go 在上海开
    3. 课程包含,周期,价格,通过学校创建课程
    4. 通过学校创建班级, 班级关联课程、讲师
    5. 创建学员时,选择学校,关联班级
    5. 创建讲师角色时要关联学校,
    6. 提供两个角色接口
    6.1 学员视图, 可以注册, 交学费, 选择班级,
    6.2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩
    6.3 管理视图,创建讲师, 创建班级,创建课程
    7. 上面的操作产生的数据都通过pickle序列化保存到文件

    该练习思路参考:http://www.cnblogs.com/lianzhilei/p/5985333.html

  • 相关阅读:
    grafana里prometheus查询语法
    Linux 高频工具快速教程
    国内开源镜像站点汇总
    Oracle DBLINK 简单使用
    启动OpenOffice服务
    使用openoffice转pdf,详细
    ORACLE数据库误操作执行了DELETE,该如何恢复数据?
    一个 介绍 superset Kylin 以及大数据生态圈的 博文
    Kylin介绍 (很有用)
    找到一些经验,关于使用thymeleaf时遇到的一些问题
  • 原文地址:https://www.cnblogs.com/leixiaobai/p/10221894.html
Copyright © 2020-2023  润新知