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

原文地址:https://www.cnblogs.com/zhangchao0515/p/14334214.html