python -m参数的含义和用法

本文详细解析了Python的`-m`参数,它允许将Python模块作为脚本来运行。通过`-m`,可以执行含有`if __name__ == '__main__'`语句的模块,而无需明确指定模块路径。文中还探讨了`sys.path`在寻找模块过程中的作用,以及`sys.modules`如何记录已加载的模块。此外,举例说明了在什么情况下可能会使用`-m`参数,比如在不同目录结构中导入和执行模块。
该文章已生成可运行项目,

在这里插入图片描述

上一篇文章介绍了python代码的计时工具line_profiler,其可以计算每行代码的运行时间,十分之好用,但是最后的一小节有说到其在计时的同时还可以生成一个结果文件,若是有需要的话可以再使用python -m命令查看其结果。其命令使用方式如下:

python -m line_profiler test.py.lprof

由于个人比较好奇,我就多方查阅资料,但网上各位大佬的博客写的可能有点深奥,同时也并未清晰明了地展示其能达到功能,我还是花了好久才最终终于大概弄懂了这个-m的含义以及到底它有什么用。当然这可能也是因为我的理解能力较差,吼吼吼。

今天就简单解释一下python -m的含义啦。


python -h中对python -m的解释

我们平常在命令行中可能大都会使用python + 脚本名(例如python test.py)来运行脚本吧,这样其实就能看出来了python实际上就是一个命令或者说是一个软件,因此python也具有很多可用的参数,要查看这些参数可以在命令行使用python -h查看帮助文档即可。

在这个帮助文档中,可以看到对-m 的解释是:

-m mod : run library module as a script (terminates option list)

也就是将一个python library 中的模块当做脚本来运行。这里实际上可能理解能力强的人就已经能理解了,虽说理解了,但是将模块当做脚本运行有什么作用呢?

python -m 的作用及使用方法

将模块当做脚本来运行,是因为一般情况下模块是通过import后,我们再使用模块中的各种函数或者功能的。但是正如之前的某篇文章说过的一样,在python脚本中一般会有一个如下的语句:

if __name__ == "__main__":   # 这里不知道怎么打出来,只能在代码块里打了
	main()

这个语句就是防止别人调用这个脚本中会直接运行main的内容,而单独运行此脚本时则可以运行main中的内容

这里针对模块来说,模块一般是被通过import引入的,例如正则re,画图的turtle、还有site模块等。引入模块时只需要输入脚本前缀即可,不需要输入后缀.py。在python自带库中有很多模块是没有上面的if 语句的,也就是它们一般不会直接被执行(例如使用python re.py的情况),但某些库是带有这种语句的,例如site模块:
在这里插入图片描述
也就是在特定情况下我们可以将这个模块当做脚本来运行。这时候本文介绍的python -m参数就派上用场啦,python -m 表示我们把后面跟的参数当做是一个模块,运行结果也就像运行其它的python脚本一样,也会运行main中的内容,只不过这里就是特定的识别后续跟的是模块(因为是模块,所以直接写文件前缀即可)。

除上述的点外,python -m由于将后面跟的参数当做模块,因此其会到sys.path也就是python搜索所需模块的路径集去寻找对应的模块,这就有点类似系统的环境变量,当引入某个模块时,就会去到sys.path中寻找到这个模块并载入内存。sys.path是一个列表,可以自定义地增加路径。通过上面的介绍,总结一下也就是我们只要知道某个已有模块的模块名(即此模块已经被安装,例如通过pip安装的line_profiler),就可以使用python -m + 模块名 的方式执行这个模块脚本了,不需要输入模块脚本所处的绝对位置(前提是模块处于sys.path中哈)。

为了帮大家更好理解,看一下我的sys.path吧(可以放大看哈)!
在这里插入图片描述

# 这里site模块含有if __name__ == '__main__' 语句,其可以通过python -m执行,
# 但我也不知道有什么用哈,就演示一下
# site模块在我电脑上的绝对路径为 
# C:\Users\MyPC\AppData\Local\Programs\Python\Python38\Lib\site.py

python -m site
# 在命令行执行,结果为:
'''
sys.path = [
    'D:\\Backup\\桌面',
    'C:\\ProgramData\\Anaconda3\\python38.zip',
    'C:\\ProgramData\\Anaconda3\\DLLs',
    'C:\\ProgramData\\Anaconda3\\lib',
    'C:\\ProgramData\\Anaconda3',
    'C:\\Users\\MyPC\\AppData\\Roaming\\Python\\Python38\\site-packages',
    'C:\\ProgramData\\Anaconda3\\lib\\site-packages',
    'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\win32',
    'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\win32\\lib',
    'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\Pythonwin',
]
USER_BASE: 'C:\\Users\\MyPC\\AppData\\Roaming\\Python' (exists)
USER_SITE: 'C:\\Users\\MyPC\\AppData\\Roaming\\Python\\Python38\\site-packages' (exists)
ENABLE_USER_SITE: True
'''

sys.path与sys.modules

其实对于除了python sys.path路径中的各种模块外,平常使用-m的机会可能还是不多,因为正常情况下使用-m和不使用-m的结果是一样的。

很多博文写的是通过使用python直接执行脚本和使用python -m来执行脚本产生的sys.path,但不知道为啥我执行后两个的sys.path相同,我就没有进一步去理解了。读者可以自己试试哈。

# 假设命名为test.py
import sys
print(sys.path)
print(sys.modules)
# 在命令行使用python -m test和python test.py的产生的sys.path结果相同。
# 产生的sys.modules的结果不同

python运行某脚本时所有加载到内存的模块都放在sys.modules中,使用python运行脚本和使用python -m两种方式不同的地方在于

  • main’: <module ‘main’ from ‘test.py’ # (普通方式)
  • main’: <module ‘test’ from ‘D:\Backup\桌面\test.py’ # (-m方式)

可以看出后者被当做了模块,前者则是脚本中的main被当做了模块。

可能使用python -m的情况

虽说使用机会少,但是看了网上博主们的博客后发现还是有可能用上的。举个例子就行啦:

比如我这里有一个test.py和一个文件夹123,文件夹中还有一个n.py

# test.py内容
# nothing

# n.py内容
import sys
import test
print(sys.path)
print(sys.modules)

在这里插入图片描述
在命令行使用:

python -m 123.n
# 这个命令是可以运行的,也就是123.n被当做了模块,这或许也是python各种库的
# 组成方式吧,不是很懂,先使用一下吧。在123文件夹中的n.py写上import test 可能大家觉得不太行,
# 但是实际上是可以的哦,这是因为sys.path在这种方式下是包含了上一级目录的,也就是包含123这个文件夹
# 和test.py这个文件的路径。大家可以多理解一下下!
# 这种使用点号的方式也不是很懂,以后再慢慢学习吧!

这种方式的使用使我们在需要导入某个脚本时不用一定要移动脚本,还是会有一定用处的哈。我觉得平常在自己的脚本中能使用的可能就是这种情况啦!不过实际上要达到这样的功能,可以直接在每个文件夹中加入一个额外的__init__.py,这样也可以解决问题的哦,这个部分了解不多,可以在网上看看其它内容哦!

实际上我也还有点不是很懂,先写下这些,哈哈,以后有更深的理解再把内容加上。

参考:与python -m命令有关的问题
参考:python sys.modules
参考:Python的-m参数

本文章已经生成可运行项目
<think>我们正在讨论Python命令行中的`-m`参数。根据引用[4][5],`python -m`的官方解释是:`run library module as a script`(将库模块作为脚本运行)。这意味着我们可以通过模块名来运行一个模块,就像运行脚本一样。 ### 核心概念 1. **模块与脚本的区别**: - 模块(Module):通常是一个包含Python代码的文件(`.py`),用于被其他模块导入使用。 - 脚本(Script):可以直接运行的Python文件。 2. **`if __name__ == '__main__'`的作用**: 在模块中,我们经常看到这样的代码: ```python if __name__ == '__main__': # 当模块被直接运行时执行 ``` 这里,`__name__`是Python的一个内置变量。当模块被直接运行时,`__name__`的值为`'__main__'`;当模块被导入时,`__name__`的值为模块的名字(即文件名去掉`.py`)。 3. **`python -m`的工作方式**: - 使用`python -m module_name`时,Python会在`sys.path`中查找名为`module_name`的模块,然后将其作为主程序执行(即触发其`if __name__ == '__main__'`块)。 - 与直接运行脚本(`python script.py`)的区别在于,`-m`方式会考虑模块的包结构,并且会先执行模块的导入动作(但不会重复执行已经导入的模块)。 ### 使用场景对比 #### 场景1:直接运行脚本 ```bash python my_script.py ``` - 将`my_script.py`作为主程序执行。 - 文件路径可以是相对路径或绝对路径。 #### 场景2:以模块方式运行 ```bash python -m my_module ``` - 将`my_module`当作模块来运行,Python会按照模块导入的规则来定位它。 - 模块名可以包含点(`.`),例如`python -m package.subpackage.module`,表示运行一个包中的子模块。 ### 实际差异 1. **模块搜索路径(`sys.path`)**: - 使用`-m`时,当前目录(运行命令的目录)会被添加到`sys.path`的开头,因此可以像导入模块一样运行当前目录下的模块。 - 直接运行脚本时,脚本所在的目录会被添加到`sys.path`的开头。 2. **包处理**: - 使用`-m`可以运行包内的模块(包括子包),而直接运行脚本则可能破坏包结构(因为脚本运行不会设置包相关的变量,如`__package__`)。 3. **相对导入**: - 在包内的模块中,如果使用相对导入(如`from . import sibling`),那么该模块必须作为模块运行(使用`-m`)才能正确导入。如果直接运行,会报错`ImportError: attempted relative import with no known parent package`。 ### 示例说明 假设我们有如下目录结构: ``` project/ package/ __init__.py module.py subpackage/ __init__.py submodule.py ``` #### 示例1:运行包内模块 在`project`目录下,运行: ```bash python -m package.module ``` - Python会找到`package.module`模块,并执行其`__main__`块(如果有的话)。 - 在`module.py`中,可以使用相对导入(如`from .subpackage import submodule`)而不会出错。 #### 示例2:直接运行包内模块 在`project`目录下,运行: ```bash python package/module.py ``` - 此时,由于直接运行脚本,`__package__`变量不会被设置为`package`,而是`None`。 - 如果`module.py`中有相对导入,则会报错。 ### 其他用途 1. **运行标准库模块**: Python标准库中的许多模块设计为既可以导入使用,也可以作为脚本运行。例如: ```bash python -m http.server # 启动一个简单的HTTP服务器 python -m json.tool # 格式化JSON ``` 2. **运行包内的`__main__.py`**: 如果一个包内包含`__main__.py`文件,那么运行`python -m package_name`时,实际上会执行`__main__.py`的内容。例如: ```bash python -m package_name ``` 相当于执行`package_name`目录下的`__main__.py`。 ### 总结 `python -m`参数的主要作用是将模块当作脚本运行,这种方式: - 遵循Python的模块导入机制 - 正确处理包结构相对导入 - 将当前目录添加到`sys.path`,便于定位模块 - 可以运行标准库模块或自定义包中的模块 因此,在开发可复用的包时,推荐使用`python -m`来运行模块,以保持包结构的完整性。 ### 相关问题 1. 为什么在包内使用相对导入时,直接运行脚本会失败? 2. 如何通过`python -m`运行一个包中的`__main__.py`? 3. `python -m``python -c`有什么区别? 4. 在命令行中,如何查看Python标准库中有哪些模块可以作为脚本运行? 5. 使用`python -m`运行模块时,如何传递命令行参数? [^1]: 参考了关于`python -m`参数含义用法的解释 [^2]: 对比了`python filename.py``python -m filename.py`的区别 [^3]: 解释了模块作为脚本运行时`if __name__ == '__main__'`的作用 [^4]: 提供了`python -h`中关于`-m`参数的官方说明 [^5]: 补充了`python -h`中关于`-m`参数的详细选项</think>### Python命令行中 `-m` 参数的作用详解 `-m` 参数Python 命令行中一个强大的功能,其核心作用是将**模块作为脚本运行**(run library module as a script)。以下是其关键意义实际应用场景: #### 1. 模块与脚本的本质区别 - **模块导入**:`import module` 仅加载模块内容,不触发执行 - **脚本运行**:`python script.py` 直接执行文件内容 - **`-m` 的独特定位**:使模块像脚本一样执行(`python -m module`),同时保留模块特性 #### 2. 核心功能解析 ```bash python -m module_name [arguments] ``` - **模块搜索机制**:优先在 `sys.path` 中查找模块(包括标准库第三方包) - **执行入口**:触发模块的 `__name__ == "__main__"` 代码块[^3] - **环境隔离**:自动设置正确的包上下文(`__package__` 变量) #### 3. 与直接运行脚本的关键区别 | 特性 | `python script.py` | `python -m module` | |------|---------------------|-------------------| | 路径解析 | 基于当前目录 | 基于模块搜索路径 | | 包结构支持 | 有限(破坏相对导入) | 完整支持包结构 | | `__name__` 值 | `"__main__"` | `"__main__"` | | `__package__` 值 | `None` | 自动设置包名 | | 相对导入 | 不可用 | 可用 | #### 4. 典型应用场景 **(1) 运行包内模块(保留包上下文)** ```bash # 正确执行包内的子模块(支持相对导入) python -m my_package.submodule ``` **(2) 使用标准库工具** ```bash # 启动 HTTP 服务器 python -m http.server 8000 # JSON 格式化工具 echo '{"name":"John"}' | python -m json.tool ``` **(3) 调试包结构** ```bash # 查看模块搜索路径 python -m site # 验证包安装位置 python -m pip show requests ``` **(4) 执行开发中的模块** ```bash # 无需安装即可测试模块(自动处理依赖路径) python -m my_dev_module ``` #### 5. 技术原理深度解析 当执行 `python -m module` 时: 1. 解释器在 `sys.path` 中定位目标模块 2. 将模块的 `__name__` 设置为 `"__main__"` 3. 设置 `sys.argv[0]` 为模块的完整路径 4. 执行模块顶层的代码(如同导入) 5. **关键区别**:触发 `if __name__ == "__main__":` 代码块 #### 6. 实际案例演示 假设有包结构: ``` myapp/ ├── __init__.py └── cli.py ``` `cli.py` 内容: ```python def main(): print("运行成功!") if __name__ == "__main__": main() ``` **正确执行方式**: ```bash # 从任意位置执行(保留包上下文) python -m myapp.cli ``` #### 7. 特殊注意事项 1. **路径陷阱**:`-m` 要求模块必须在 `sys.path` 中 2. **入口文件**:包目录中的 `__main__.py` 可通过 `python -m package` 直接执行 3. **参数传递**:`-m` 后的所有参数传递给模块的 `sys.argv` > 通过 `python -m` 运行模块,既保持了模块的可导入性,又获得了脚本的直接执行能力,是 Python 生态中模块化开发的最佳实践[^2][^3]。 ### 相关问题 1. 为什么在包内使用相对导入时,必须通过 `python -m` 执行? 2. 如何查看当前 Python 环境中所有可用 `-m` 执行的模块? 3. `python -m pip install` 直接运行 `pip` 命令有何区别? 4. 在什么场景下应该优先使用 `python -m` 而非直接运行脚本? 5. 如何为自定义包创建可通过 `python -m package` 执行的入口? [^1]: 解释了 `python -m` 的基本概念执行机制 [^2]: 对比了直接运行脚本与 `-m` 方式的差异 [^3]: 说明了模块中 `if __name__ == '__main__'` 的作用 [^4]: 提供了官方命令行帮助文档的说明 [^5]: 补充了 `-m` 在命令行选项中的位置说明
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值