zoukankan      html  css  js  c++  java
  • [转]python3 跨目录模块调用,你真的懂了吗?

    小伙伴们,你们有遇到过调用自己写的模块(跨目录模块调用),提示你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())

    执行代码报错

     

    解释出错原因

    查看刚才的报错信息,我们可以知道,我们在执行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中的导包方式不会引发异常呢?


    作者:亭子青年
    链接:https://www.jianshu.com/p/61ed747680e2
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    [DB] 数据库的连接
    JS leetcode 翻转字符串里的单词 题解分析
    JS leetcode 拥有最多糖果的孩子 题解分析,六一快乐。
    JS leetcode 搜索插入位置 题解分析
    JS leetcode 杨辉三角Ⅱ 题解分析
    JS leetcode 寻找数组的中心索引 题解分析
    JS leetcode 移除元素 题解分析
    JS leetcode 最大连续1的个数 题解分析
    JS leetcode 两数之和 II
    JS leetcode 反转字符串 题解分析
  • 原文地址:https://www.cnblogs.com/champaign/p/10895654.html
Copyright © 2011-2022 走看看