• Python 模块(Module)调用


    2021-01-27

    首先我们需要了解一下基础:

    参考我的博客:https://www.cnblogs.com/zhangchao0515/p/14333370.html

    接下来,我们讲的重点是 Python 模块(Module)调用

    主要有以下5种方法:
    1. python默认的模块导入执行过程--
      1) 要么是同一目录下,可以相互调用
      2) 要么是在子目录下,可以从当前模块往下
        (都是需要__init__.py,而且是根据python自己的机制)
      针对1)和2)是默认的机制-- python会自动将该文件的的路径临时添加到环境变量中,类似在文件中 sys.path.append('当前py文件目录')

    2. 要么在当前的py文件中将项目根目录加入 -- 作用域是当前py文件
      sys.path.append('项目根目录')

    3. 先在cmd中设置环境变量,作用域是当前的cmd窗口   -- pycharm 就是类似这种效果,可以测试一下
      1) set PYTHONPATH=D:Projectspythonvscodepython-module
        可以通过命令查看:echo %PYTHONPATH%
      2)执行文件
        python xxx.py

    4. 设置全局变量 -- 作用域是一直存在
      PYTHONPATH=D:Projectspythonvscodepython-module
     
    5. 把文件添加到默认路径中 -- 还是算了吧,一般都不用这种的。除非是针对python的封装等,比如Anaconda等。
     

    一、我们先创建一个测试项目python-module

    1、搜索路径

    当你导入一个模块,Python 解析器对模块位置的搜索顺序是:

    • 1、当前目录
    • 2、如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
    • 3、如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。

    模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

    2、Python中的包

    包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的 Python 的应用环境。

    简单来说,包就是文件夹,但该文件夹下必须存在 __init__.py 文件, 该文件的内容可以为空。__init__.py 用于标识当前文件夹是一个包。

    3、目录结构如下

    目录是D:Projectspythonvscodepython-module

    python-module
      src
        main
          package1
            __init__.py
            module1.py
          package2
            package3
              __init__.py
              module2.py
            __init__.py
            module2.py
            moduletest1.py
            moduletest2.py
            moduletest3.py
            moduletest4.py
        test

    4、文件说明

    1) 首先我们创建目录 python-modulesrcmain和python-modulesrc est
    2) 然后在python-modulesrcmain创建包
    比如python-modulesrcmainpackage1,python-modulesrcmainpackage1\__init__.py
    python-modulesrcmainpackage2, python-modulesrcmainpackage2\__init__.py
    python-modulesrcmainpackage2package3, python-modulesrcmainpackage2package3\__init__.py
    3) 创建py文件
    python-modulesrcmainpackage1module1.py
    python-modulesrcmainpackage2module2.py
    python-modulesrcmainpackage2moduletest1.py
    python-modulesrcmainpackage2moduletest2.py
    python-modulesrcmainpackage2moduletest3.py
    python-modulesrcmainpackage2moduletest4.py
    python-modulesrcmainpackage2package3module3.py
    4) 文件简要说明
    module1.py module2.py module3.py是我们的待测试代码
    moduletest1.py moduletest2.py moduletest3.py moduletest4.py是针对四种场景的测试代码
    5)代码
    module1.py 如下所示:
    def fun1():
      print ("我是来自 module1")

    module2.py 如下所示:

    def fun2():
      print ("我是来自 module2")

    module3.py 如下所示:

    def fun3():
      print ("我是来自 module3")

    5、执行方法

    1)打开cmd 

    2)切换到要执行的py目录下

    3)执行py

    例如:

    python moduletest1.py

    一、python默认的模块导入执行过程

    我们知道了搜索路径,我们直接考虑第一种搜索:

    当你导入一个模块,Python 解析器对模块位置的搜索顺序是:

    • 1、当前目录
    • 2、如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
    • 3、如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。

    模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

    会先搜索当前目录,其实就是把当前目录临时添加到环境变量,作用域仅限于该py文件。由此引入了方法1

    1. python默认的模块导入执行过程--
      1) 要么是同一目录下,可以相互调用
      2) 要么是在子目录下,可以从当前模块往下
        (都是需要__init__.py,而且是根据python自己的机制)
      针对1)和2)是默认的机制-- python会自动将该文件的的路径临时添加到环境变量中,类似在文件中 sys.path.append('当前py文件目录')

    1、首先我们先打印一下 sys.path看一下环境

    moduletest1.py如下

    import sys
    # 测试第一种:使用python默认的模块导入机制
    # 只能导入同一目录或子目录下的模块,效果类似 sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    # python moduletest1.py -- 作用域只是当前的python
    
    
    if __name__ == '__main__':
      print(sys.path)

    打开cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

     我们可以看到,默认就会把该目录添加到环境变量中。

    2、我们直接引入模块module2.py和module3.py

    moduletest1.py如下

    import sys
    # 测试第一种:使用python默认的模块导入机制
    # 只能导入同一目录或子目录下的模块,效果类似 sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    # python moduletest1.py -- 作用域只是当前的python
    
    # 1. 这个是在同一目录下,可以相互调用。效果类似在该文件中添加 sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    from module2 import fun2
    # 2. 这个是在子目录下,只能自己调用子目录的,反过来不行。效果类似在该文件中添加 sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    from package3.module3 import fun3
    # 3. 会报错,不识别模块package1
    # from package1.module1 import fun1
    
    if __name__ == '__main__':
      print(sys.path)
      fun2()
      fun3()
      # fun1()

    打开cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

     这是因为:搜索路径,会先搜索当前目录

    3、我们再引入模块module1.py

    moduletest1.py如下
    import sys
    # 测试第一种:使用python默认的模块导入机制
    # 只能导入同一目录或子目录下的模块,效果类似 sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    # python moduletest1.py -- 作用域只是当前的python
    
    # 1. 这个是在同一目录下,可以相互调用。效果类似在该文件中添加 sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    from module2 import fun2
    # 2. 这个是在子目录下,只能自己调用子目录的,反过来不行。效果类似在该文件中添加 sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    from package3.module3 import fun3
    # 3. 会报错,不识别模块package1
    from package1.module1 import fun1
    
    if __name__ == '__main__':
      print(sys.path)
      fun2()
      fun3()
      fun1()

    打开cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

     那是因为他不会往上级目录搜索

    二、通过sys.path.append 或者sys.path.exclude临时导入环境变量

    当你导入一个模块,Python 解析器对模块位置的搜索顺序是:

    • 1、当前目录
    • 2、如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
    • 3、如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。

    模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

    通过sys.path.append 或者sys.path.exclude临时导入环境变量,它的作用域也只是该py文件。

    1、按照惯例先看一下sys.path

    moduletest2.py如下

    import sys
    # 测试第二种:
    # 在文件中添加 sys.path.append('项目根目录'), sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    # python moduletest2.py -- 作用域只是当前的python
    if __name__ == '__main__':
      print(sys.path)

    打开cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

     2、我们直接引入模块module1.py和module2.py和module3.py

    moduletest2.py如下

    import sys
    import os
    # 测试第二种:
    # 在文件中添加 sys.path.append('项目根目录'), sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    # python moduletest2.py -- 作用域只是当前的python
    # 获取当前文件的目录
    # curpath = os.path.abspath(os.path.dirname(__file__))
    # 获取项目根目录 D:\Projects\python\vscode\python-module
    projectpath = os.path.abspath(os.path.dirname(__file__)+r'../../../')
    
    # 1. 在该文件中添加 sys.path.append('项目根目录') -- 作用域只是当前py文件
    sys.path.append(projectpath)
    
    from src.main.package2.module2 import fun2
    # 2. 在该文件中添加 sys.path.append('当前文件所在的目录') ,python默认会把该目录加入,不需要这步操作 -- 作用域只是当前py文件
    # sys.path.append(curpath)
    # from module2 import fun2
    from src.main.package2.package3.module3 import fun3
    from src.main.package1.module1 import fun1
    
    
    if __name__ == '__main__':
      print(sys.path)
      fun2()
      fun3()
      fun1()

    打开cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

     所以,环境变量里面一个是自动添加的目录,一个是我们自己添加的目录,两个同样的作用域是该py文件。且都是临时的。

    自动添加的:'D:\Projects\python\vscode\python-module\src\main\package2'
    我们添加的:'D:\Projects\python\vscode\python-module'

    由此我们可以添加'D:\Projects\python\vscode\python-module'目录下的模块,需要引入相关包。该方法不能动源码结构,否则要大量修改源码。

    当然我们的包名引入还可以用一的,因为也存在 'D:\Projects\python\vscode\python-module\src\main\package2'。

    3、混用这两个路径

    moduletest2_1.py如下

    import sys
    import os
    # 测试第二种:
    # 在文件中添加 sys.path.append('项目根目录'), sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    # python moduletest2_1.py -- 作用域只是当前的python
    # 获取当前文件的目录
    # curpath = os.path.abspath(os.path.dirname(__file__))
    # 获取项目根目录 D:\Projects\python\vscode\python-module
    projectpath = os.path.abspath(os.path.dirname(__file__)+r'../../../')
    
    # 1. 在该文件中添加 sys.path.append('项目根目录') -- 作用域只是当前py文件
    sys.path.append(projectpath)
    
    # 很明显用这个路径'D:\Projects\python\vscode\python-module\src\main\package2'
    from module2 import fun2
    from package3.module3 import fun3
    # 很明显用这个路径 D:\Projects\python\vscode\python-module
    from src.main.package1.module1 import fun1
    
    
    if __name__ == '__main__':
      print(sys.path)
      fun2()
      fun3()
      fun1()

    打开cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

    真会玩!!!

    4、我们再引入模块module1.py和module2.py和module3.py

    moduletest2_2.py如下

    import sys
    import os
    # 测试第二种:
    # 在文件中添加 sys.path.append('项目根目录'), sys.path.append('当前文件所在的目录') -- 作用域只是当前py文件
    # python moduletest2_2.py -- 作用域只是当前的python
    # 获取当前文件的目录
    # curpath = os.path.abspath(os.path.dirname(__file__))
    # 获取项目的main目录 D:\Projects\python\vscode\python-module\src\main
    mainpath = os.path.abspath(os.path.dirname(__file__)+r'../')
    
    # 1. 在该文件中添加 sys.path.append('项目根main目录') -- 作用域只是当前py文件
    sys.path.append(mainpath)
    
    from package2.module2 import fun2
    from package2.package3.module3 import fun3
    from package1.module1 import fun1
    
    
    if __name__ == '__main__':
      print(sys.path)
      fun2()
      fun3()
      fun1()

    打开cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

    是不是类似java的包,好会玩,快被玩坏了!!!

    三、在命令窗口设置 PYTHONPATH

    当你导入一个模块,Python 解析器对模块位置的搜索顺序是:

    • 1、当前目录
    • 2、如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
    • 3、如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。

    模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

    这里我们就用到第2种搜索

    1、按照惯例,先看一下sys.path

    moduletest3.py如下

    import sys
    
    
    if __name__ == '__main__':
      print(sys.path)

    打开cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

    2、在命令行设置PYTHONPATH -- 作用域是该窗口,只要窗口不关闭,在窗口中执行就行

    moduletest3.py如下

    import sys
    
    
    if __name__ == '__main__':
      print(sys.path)

    打开cmd,执行

    set PYTHONPATH=D:Projectspythonvscodepython-module
    echo %PYTHONPATH%

    结果如下所示:

     切换到该文件所在目录,再次执行 

    python moduletest1.py

    结果如下所示:

     在该环境变量中:

    自动添加的:'D:\Projects\python\vscode\python-module\src\main\package2'
    我们添加的:'D:\Projects\python\vscode\python-module'

    由此我们可以添加'D:\Projects\python\vscode\python-module'目录下的模块,需要引入相关包。

    这里的作用域是该窗口。

    3、引入模块module1.py和module2.py和module3.py

    moduletest3.py如下

    import sys
    # 测试第三种:在cmd中切换到该目录下,执行 set PYTHONPATH=D:\Projects\python\vscode\python-module
    # 我们可以查看 echo %PYTHONPATH%
    # 作用域是该cmd窗口,这要窗口下执行,都是有该环境变量存在
    # python moduletest3.py
    
    
    from src.main.package2.module2 import fun2
    from src.main.package2.package3.module3 import fun3
    from src.main.package1.module1 import fun1
    
    
    if __name__ == '__main__':
      print(sys.path)
      fun2()
      fun3()
      fun1()

    在刚才窗口中执行 

    python moduletest1.py

    结果如下所示:

    如果窗口没有设置 PYTHONPATH,肯定会报错。

    什么?你不信!!!

    那我们就测试一下

    重新打开一个窗口或者在该窗口执行以下操作:

    set PYTHONPATH=

    结果如下:

    在刚才窗口中执行 

    python moduletest1.py

    结果如下所示:

    我就说嘛,请不要抬杠!!!

    4、如果是在pycharm中,则不会报错,不需要在命令行设置PYTHONPATH,因为pycharm已经设置好了

    注意!!!好玩的又来了。

    有些会问,我没有设置PYTHONPATH,为什么在pycharm没有报错,那是因为pycharm已经设置好了。

    pycharm就是采用类似这种的策略。

    1)我们打开pycharm,导入该项目,看一下

    打开 File --> Settings --> Build,Execution,Deployment --> Console --> Python Console

     我们看一下启动脚本 Starting script

    import sys; print('Python %s on %s' % (sys.version, sys.platform))
    sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])

    好家伙!!!

    启动脚本肯定是先执行的。 -- 至于如何设计,不太清楚,你们研究好了可以告诉我一声,我谢谢啊。

    (1) 这里面先引入 import sys;

    (2) 之后调用print('Python %s on %s' % (sys.version, sys.platform))打印信息,

    我的打印结果是

     也就是说

    sys.version: 3.8.3 (default, Jul  2 2020, 17:30:36) [MSC v.1916 64 bit (AMD64)]
    sys.platform: win32

    (3) 然后是 sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]),把目录添加到环境变量中,

    至于WORKING_DIR_AND_PYTHON_PATHS是识别不了的,pycharm肯定在其他地方定义了。

    不过幸亏这名字取得我们能看懂意思,就是就是工作目录和python目录。

    这里的工作目录一看就是项目目录。我们可以验证一下。

    2)我们已经把项目导入了pycharm,我们执行 moduletest3.py 试试看

    当然我们这里什么都没设置

    moduletest3.py如下:-- 和之前一样

    import sys
    # 测试第三种:在cmd中切换到该目录下,执行 set PYTHONPATH=D:\Projects\python\vscode\python-module
    # 我们可以查看 echo %PYTHONPATH%
    # 作用域是该cmd窗口,这要窗口下执行,都是有该环境变量存在
    # python moduletest3.py
    
    
    from src.main.package2.module2 import fun2
    from src.main.package2.package3.module3 import fun3
    from src.main.package1.module1 import fun1
    
    
    if __name__ == '__main__':
      print(sys.path)
      fun2()
      fun3()
      fun1()

    我们直接点pycharm的执行

    结果如下:

     我们把结果的内容复制下来:

    D:ProgramFilesAnaconda3python.exe D:/Projects/python/vscode/python-module/src/main/package2/moduletest3.py
    ['D:\Projects\python\vscode\python-module\src\main\package2', 
    'D:\Projects\python\vscode\python-module', 
    'D:\ProgramFiles\JetBrains\PyCharm 2020.1\plugins\python\helpers\pycharm_display', 
    'D:\ProgramFiles\Anaconda3\python38.zip', 
    'D:\ProgramFiles\Anaconda3\DLLs', 
    'D:\ProgramFiles\Anaconda3\lib', 
    'D:\ProgramFiles\Anaconda3', 
    'D:\ProgramFiles\Anaconda3\lib\site-packages', 
    'D:\ProgramFiles\Anaconda3\lib\site-packages\win32', 
    'D:\ProgramFiles\Anaconda3\lib\site-packages\win32\lib', 
    'D:\ProgramFiles\Anaconda3\lib\site-packages\Pythonwin', 
    'D:\ProgramFiles\JetBrains\PyCharm 2020.1\plugins\python\helpers\pycharm_matplotlib_backend']
    我是来自 module2
    我是来自 module3
    我是来自 module1
    
    Process finished with exit code 0

    我的天,sys.path 中包含

    'D:\Projects\python\vscode\python-module\src\main\package2', 
    'D:\Projects\python\vscode\python-module'

    所以嘛,不要抬杠!!!

    四、设置全局变量 -- 作用域是一直存在

    1、添加环境变量 

    PYTHONPATH=D:Projectspythonvscodepython-module
    方法: 
    对于Windows,右键我的电脑 --> 属性 --> 高级系统设置 --> 环境变量 --> 既可以添加用户环境变量,也可以添加系统环境变量 -->
     新建 --> 添加变量名:PYTHONPATH,添加变量值:D:Projectspythonvscodepython-module --> 确定

     2、按照惯例,我们测试一下sys.path

    moduletest4.py如下

    import sys
    # 测试第四种:设置全局变量 -- 作用域是一直存在
    # 对于Windows,右键我的电脑 --> 属性 --> 高级系统设置 --> 环境变量 --> 既可以添加用户环境变量,也可以添加系统环境变量 -->
    # 新建 --> 添加变量名:PYTHONPATH,添加变量值:D:Projectspythonvscodepython-module --> 确定
    # python moduletest4.py 
    
    
    if __name__ == '__main__':
      print(sys.path)

    打开新的cmd(老的还是老配置,只有新的),切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

    sys.path 中包含

    'D:\Projects\python\vscode\python-module\src\main\package2', 
    'D:\Projects\python\vscode\python-module'

    3、我们直接引入模块module1.py和module2.py和module3.py

    moduletest4.py如下

    import sys
    # 测试第四种:设置全局变量 -- 作用域是一直存在
    # 对于Windows,右键我的电脑 --> 属性 --> 高级系统设置 --> 环境变量 --> 既可以添加用户环境变量,也可以添加系统环境变量 -->
    # 新建 --> 添加变量名:PYTHONPATH,添加变量值:D:Projectspythonvscodepython-module --> 确定
    # python moduletest4.py 
    
    
    from src.main.package2.module2 import fun2
    from src.main.package2.package3.module3 import fun3
    from src.main.package1.module1 import fun1
    
    
    if __name__ == '__main__':
      print(sys.path)
      fun2()
      fun3()
      fun1()

    打开新的cmd,切换到该文件所在目录,执行 

    python moduletest1.py

    结果如下所示:

     

     五、把文件添加到默认路径中 -- 还是算了吧,一般都不用这种的。

    除非是针对python的封装等,比如Anaconda等。请自行解决。

    当你导入一个模块,Python 解析器对模块位置的搜索顺序是:

    • 1、当前目录
    • 2、如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
    • 3、如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。

    模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

     总结:

    1、按照自动搜索方法,会先搜索当前目录,但是该方法的缺点是不能识别上级目录的模块,并且作用域只是该py文件

    2、自己在py中添加环境变量,会识别本目录,以及从添加目录开始的模块,但是该方法的缺点是每个py文件都要添加环境变量,并且作用域只是该py文件

    3、打开cmd,设置本窗口的变量。 set PYTHONPATH=D:\Projects\python\vscode\python-module,可以通过 echo %PYTHONPATH% 查看。这么设置的话,作用域是本窗口。

    4、设置全局的环境变量。作用域一直存在。我们不需要了在删除之。

    5、把文件添加到默认路径中。

    参考:Python 模块 - https://www.runoob.com/python/python-modules.html

  • 相关阅读:
    day10 测试2
    算法题
    day10 自动化测试
    day09 测试
    进行试验,对比
    多层网络的SIR实现
    day08 商城项目
    day07 cookie session 模板
    day06 模型类
    纸上谈兵:图(graph)
  • 原文地址:https://www.cnblogs.com/zhangchao0515/p/14334214.html
Copyright © 2020-2023  润新知