美文网首页颠覆你的Python实践软件测试软件测试之路
python3 跨目录模块调用,你真的懂了吗?

python3 跨目录模块调用,你真的懂了吗?

作者: 亭子青年 | 来源:发表于2017-09-06 14:21 被阅读238次

    概述

    我还是那个没有收到offer,在家带着孩子,学着测试的宝妈。

    正文

    小伙伴们,你们有遇到过调用自己写的模块(跨目录模块调用),提示你ImportError:No module named ...的情况,如果有,而且到现在还没有搞明白的,我想说,你今天看对文章了。

    这篇文章主要是讲解怎么还原一个出错的场景,然后分析出错原因,一步一步的解决这个问题的思路。


    项目结构

    项目结构

    代码内容

    # model1/student.py
    def get_name():
        return "hting"
    
    # model1/new_student.py
    from student import get_name   #注意这里的导入包的方式,会导致后面的异常
    
    def get_student_name():
        return get_name()
    
    # model2/animal.py
    def get_name():
        return "dog"
    
    # model2/new_animal.py
    from model2.animal import get_name #注意这里的导入包的方式,和model1中new_student.py模块中的导入方式有什么不一样
    
    def get_student_name():
        return get_name()
    

    注意上面脚本导入包的方式,和model1中new_student.py模块中的导入方式有什么不一样

    # testModel/test.py 这里是运行入口
    from model1 import student
    from model1 import new_student
    from model2 import animal
    from model2 import new_animal
    if __name__ == "__main__":
        print(student.get_name())
        print(new_student.get_student_name())
        print(animal.get_name())
        print(new_animal.get_student_name())
    

    执行代码报错

    image.png

    解释出错原因

    查看刚才的报错信息,我们可以知道,我们在执行test.py这个文件的时候,找不到student这个对象,那么我们找到包含“from student import get_name”的这个文件“new_student.py”,执行这个文件,没有报错,所以,这样写是绝对没有问题的,那么为什么我们在外部对new_student.py这个模块调用的时候会报错?这里就要涉及到我们的python导包顺序了。
    (1)第一步:查找执行文件所在目录
    (2)第二步:查找执行文件所属的项目目录
    (3)第三步:查找path环境配置的目录

    根据我的实验,其实所谓的导包顺序都是根据path中配置顺序来的。我们做个实验,在test.py中将path变量打印出来,结果如下

    ['C:\\HOMETing\\ForPython\\testforpath\\testModel',   # 执行文件的所在目录
    'C:\\Python35\\lib\\site-packages\\django-2.0-py3.5.egg', 
    'C:\\Python35\\lib\\site-packages\\pytz-2017.2-py3.5.egg',
     'C:\\HOMETing\\ForPython\\testforpath', # 执行文件所在项目的根目录
     'C:\\Python35\\python35.zip',
     'C:\\Python35\\DLLs', 
    'C:\\Python35\\lib', 
    'C:\\Python35', 
    'C:\\Python35\\lib\\site-packages']
    

    结合我们这个问题,会执行这样的步骤
    (1)查找执行文件的所在目录,没有student这个对象
    (2)查找项目的根目录下,没有student这个对象
    (3)查找path中的其他目录也是没有这个student对象的
    (4)执行上面4个步骤之后都没有找到这个对象,所以报错

    根据上面的分析,多少应该有了解决思路:就是将我们student所在的目录加入到path变量中。

    解决这个问题

    根据上面步骤的分析,我们尝试将model1这个包路径加入到path变量中,看是否解决了问题。
    在代码中添加如下代码

    import sys
    sys.path.append("../model1")
    

    test.py模块修改之后的代码

    # test.py
    import sys
    sys.path.append("../model1")
    # print(sys.path)   # 打印出path,调试使用
    from model1 import student
    from model1 import new_student
    from model2 import animal
    from model2 import new_animal
    if __name__ == "__main__":
        print(student.get_name())
        print(new_student.get_student_name())
        print(animal.get_name())
        print(new_animal.get_student_name())
    

    运行结果

    运行成功.png

    到此,问题已经解决。

    我们使用print(sys.path)将path打印出来看一下

    [
        'C:\\HOMETing\\ForPython\\testforpath\\testModel', 
        'C:\\Python35\\lib\\site-packages\\django-2.0-py3.5.egg',
        'C:\\Python35\\lib\\site-packages\\pytz-2017.2-py3.5.egg',
        'C:\\HOMETing\\ForPython\\testforpath',
        'C:\\Python35\\python35.zip', 
       'C:\\Python35\\DLLs', 
       'C:\\Python35\\lib',
       'C:\\Python35',
       'C:\\Python35\\lib\\site-packages',
        '../model1' # 新加入的path
    ]
    
    

    另外:我建议不要使用将相对变量的路径加入到path中,建议使用绝对变量。方法如下

    import sys
    import os
    sys.path.append(os.path.abspath("../model1"))
    
    # os.path.abspath(path)   
    # 返回path规范化的绝对路径。 
    

    练习题

    读完这篇文章,我相信小伙伴们肯定是有收获的,那么我们尝试着做一个简单的题来巩固一下。

    为什么new_student.py中的导包方式不会引发异常呢?

    这个问题就留给小伙伴们自己想了,如果小伙伴们认真的看了我的这篇文章,我相信,你是可以找到问题所在的。

    当然,你也可以选择留言。

    相关文章

      网友评论

      • yuanbuyuan:谢谢你,这篇文章对我帮助很大。
      • 蓝山_阑珊:按照你的操作步骤,感觉目录结构应该是:
        -- testforpath
        |-- model1
        | |-- __init__.py
        | |-- new_student.py
        | |-- student.py
        |-- model2
        | |-- __init__.py
        | |-- new_animal.py
        | |-- animal.py
        |-- test.py
        test.py 应该和model1、model2平级
        亭子青年:@阑珊20170222 我这里没有这个问题,你看你和我的代码是否一致
        蓝山_阑珊:我还有一点不明白:直接运行new_animal.py,会报错ImportError: No module named 'model2',而运行test.py却不报错,为什么?
        亭子青年:@阑珊20170222 这样也可以,但是如果按照我的方式来,你就可以思考,为什么我在testmodel 文件夹下的文件可以直接调用父级目录下的包了。

        而且一般项目中,我们的愿意将代码文件分模块的放入某个文件夹或者包中。只有少数的文件会被放置到根目录。

        厉害了,居然实战了:smile::smile:
      • 秋之川:都开始留题目了,赞一个

      本文标题:python3 跨目录模块调用,你真的懂了吗?

      本文链接:https://www.haomeiwen.com/subject/ihbmjxtx.html