2022年 11月 3日

【python -m】详解

普通模块应用

以“.py”为后缀的文件就是一个模块,在“-m”之后使用时,只需要使用模块名,不需要写出后缀,但前提是该模块名是有效的,且不能是用 C 语言写成的模块。
对于一个普通模块,有时候这两种写法表面看起来是等效的:
在这里插入图片描述
两种写法都会把定位到的模块脚本当成主程序入口来执行,即在执行时,该脚本的 __name__ 都是”__main__“,跟 import 导入方式是不同的。

但是,这只是看起来等效,实际是不等效的。Look一下:

(venv) weitonghui:learnSklearn vth$ python -m os
(venv) weitonghui:learnSklearn vth$ python os
/Users/vth/PycharmProjects/learnSklearn/venv/bin/python: can't open file '/Users/vth/PycharmProjects/learnSklearn/os': [Errno 2] No such file or directory
  • 1
  • 2
  • 3

python -m 会在sys.path中,找“os模块”。 而python 会在sys.path中,找“os”。
os模块就在pythonsys.path中可以找到,但os找不到,会提示No such file or directory

那么,“-m”方式与直接运行脚本相比,在实现上有什么不同呢?换句话说,凭啥-m就能找到,直接运行就找不到呢

直接运行脚本时,相当于给出了脚本的完整路径(不管是绝对路径还是相对路径),即这个路径会在所有的文件目录下找,是拼接的方式。解释器根据 文件系统的查找机制, 定位到该脚本,然后执行。
使用“-m”方式时,解释器需要在不 import 的情况下,在 所有模块命名空间 中查找,定位到脚本的路径,然后执行。为了实现这个过程,解释器会借助两个模块: pkgutilrunpy ,前者用来获取所有的模块列表,后者根据模块名来定位并执行脚本 。

包内模块(模块是个包)

如果“-m”之后要执行的是一个包,那么解释器经过前面提到的查找过程,先定位到该包,然后会去执行它的“__main__”子模块,也就是说,在包目录下需要实现一个“__main__.py”文件。
换句话说,假设有个包的名称是“pname”,那么, “python -m pname”,其实就等效于“python -m pname.__main__”。

参考文献

Python 中 -m 的典型用法、原理解析与发展演变