• python 子包调用 跨目录调用


    1. python3中的模块和包

    简单来讲,模块是一个包含Python定义和语句的文件,包是一种通过用“带点号的模块名”来构造 Python 模块命名空间的方法。

    详细可以参考廖雪峰的:python教程-模块

    本文以以下的项目结构,对python3的子包之间的调用进行探索:

    python模块 (1)

    使用的python版本:3.7.0

    平台:win10


    2. python的模块搜索路径

    当一个名为 spam 的模块被导入的时候,解释器首先寻找具有该名称的内置模块。如果没有找到,然后解释器从 sys.path 变量给出的目录列表里寻找名为 spam.py 的文件。sys.path 初始有这些目录地址:

    • 包含输入脚本的目录(或者未指定文件时的当前目录);
    • PYTHONPATH (一个包含目录名称的列表,它和shell变量 PATH 有一样的语法);
    • 取决于安装的默认设置;


    3. 调用子包与调用兄弟包

    假如在main.py中调用pack.mod1.py中的函数func1,而func1又调用pack2.mod2.py中的func2函数,各个文件中的代码如下:

    main.py:
    import sys
    print("file:{},sys.path:{}".format(__file__, sys.path))
    from pack1 import mod1
    
    if __name__ == "__main__":
        mod1.func1()
    
    
    pack1/mod1.py:
    from pack2 import mod2
    
    def func1():
        print("this is pack1.mod1")
        mod2.func2()
    

    
    pack2/mod2.py:
    def func2():
        print("this is pack2.mod2")

    进入test_mod目录,执行命令:

    python main.py

    输出:

    file:main.py,sys.path:['D:\1-Work\python_src\test_mod', 
    'C:\Users\xxx\AppData\Local\Programs\Python\Python37\python37.zip', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\DLLs', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\lib', 
    'C:\Users\xxx\AppData\Local\Programs\Python\Python37', 'C:\Users\xxx\AppData\Roaming\Python\Python37\site-packages', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\lib\site-packages']
    this is pack1.mod1
    this is pack2.mod2

    可以看出sys.path中的第一个元素,就是main.py所在的目录,因为包pack1和pack2都在这个目录下,所以它们能够互相发现。

    假如这个时候,你想单独调试一下pack1.mod1.func1函数,将mod1.py修改如下:

    import sys
    print("file:{},sys.path:{}".format(__file__, sys.path))
    from pack2 import mod2
    
    def func1():
        print("this is pack1.mod1")
        mod2.func2()
    
    if __name__ == "__main__":
        func1()

    进入pack1目录运行:

    python mod1.py

    输出如下:

    file:mod1.py,sys.path:['D:\1-Work\python_src\test_mod\pack1', 
    'C:\Users\xxx\AppData\Local\Programs\Python\Python37\python37.zip', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\DLLs', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\lib', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37', 'C:\Users\xxx\AppData\Roaming\Python\Python37\site-packages', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\lib\site-packages']
    Traceback (most recent call last):
      File "mod1.py", line 3, in <module>
        from pack2 import mod2
    ModuleNotFoundError: No module named 'pack2'

    发现sys.path的第一个路径已经是test_mod/pack1了,在这个目录下面解释器无法找到pack2这个包。

    如果需要发现这个包,按照python搜索路径的规则,需要将test_mod这个目录加入到sys.path中,一般来说可以:

    • 通过环境变量PYTHONPATH进行设置;
    • 也可以将路径写入.pth文件,Python在遍历已知的库文件目录过程中,如果见到一个.pth 文件,就会将文件中所记录的路径加入到 sys.path 中;
    • 最简单的是使用sys.path.append函数将路径加入。

    使用最后一种办法,将pack1.mod1.py修改为:

    import sys
    sys.path.append("D:\1-Work\python_src\test_mod")
    print("file:{},sys.path:{}".format(__file__, sys.path))
    from pack2 import mod2
    
    def func1():
        print("this is pack1.mod1")
        mod2.func2()
    
    if __name__ == "__main__":
        func1()

    结果输出:

    file:mod1.py,sys.path:['D:\1-Work\python_src\test_mod\pack1', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\python37.zip', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\DLLs', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\lib', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37', 'C:\Users\xxx\AppData\Roaming\Python\Python37\site-packages', 'C:\Users\xxx\AppData\Local\Programs\Python\Python37\lib\site-packages', 'D:\1-Work\python_src\test_mod']

    为什么使用绝对路径呢,因为如果使用相对路径的话,当前工作路径一变就不行了,不信在test_mod目录执行

    python pack1/mod1.py

    或者用vscode等文本编辑器打开test_mod目录,然后直接F5运行,工作目录就是test_mod,而不是pack1,这个时候添加的”../”路径就会变成目录python_src。

    这也是为什么很多文章使用sys.path.append(“../”),然后很多人在留言区说在他们本地运行的时候根本不行。

    所以一切的关键还是模块搜索路径。

    回到解决方式上面,或者将项目的路径加到PYTHONPATH环境变量,或者写入.pth并放在搜索路径中才是一劳永逸的方式。


    4. 参考

    (1) python3文档-模块

    (2) 廖雪峰:python教程-模块

    (完)

  • 相关阅读:
    svn笔记
    cakephpurl生成
    cakephp加载流程
    jquery validate使用方法
    我需要具备的知识和能力总结
    cakePHP国际化和本地化
    javascript片段收集
    ecmall一个典型的操作
    9. Technical Overview 技术概述
    42. Spring Security Dependencies春季安全依赖
  • 原文地址:https://www.cnblogs.com/harrymore/p/12292278.html
Copyright © 2020-2023  润新知