问题:-m开关的作用是什么?
你能给我解释一下打电话之间有什么区别
python -m mymod1 mymod2.py args
和
python mymod1.py mymod2.py args
看来在这两种情况下mymod1.py
被调用,sys.argv
是
['mymod1.py', 'mymod2.py', 'args']
那么,该-m
开关是做什么用的呢?
回答 0
PEP 338Rationale
部分的第一行说:
Python 2.4添加了命令行开关-m,以允许使用Python模块命名空间定位模块以作为脚本执行。激励性的示例是标准库模块,例如pdb和profile,并且Python 2.4实现对于此有限的目的是合适的。
因此,您可以通过这种方式在Python的搜索路径中指定任何模块,而不仅仅是当前目录中的文件。您是正确的,python mymod1.py mymod2.py args
其效果完全相同。本Scope of this proposal
节的第一行指出:
在Python 2.4中,将执行使用-m定位的模块,就像在命令行中提供了其文件名一样。
还有-m
更多的可能,例如使用作为包装一部分的模块等,这就是PEP 338其余部分的意义。阅读以获取更多信息。
回答 1
值得一提的是,只有在程序包具有文件的情况下__main__.py
,此方法才有效。否则,该程序包无法直接执行。
python -m some_package some_arguments
python解释器将__main__.py
在包路径中查找要执行的文件。等效于:
python path_to_package/__main__.py somearguments
它将在以下时间执行内容:
if __name__ == "__main__":
回答 2
在我看来,尽管已经多次询问并回答了这个问题(例如,在这里,在这里,在这里和在这里),但是没有一个现有的答案可以完全或简洁地捕捉到该-m
标志的所有含义。因此,以下将尝试改进之前的内容。
简介(TLDR)
该-m
命令执行了很多操作,并非始终需要所有这些命令。简而言之:(1)允许通过模块名而不是文件名执行python脚本(2)允许选择要添加到的目录以sys.path
进行import
解析,(3)允许从命令行执行具有相对导入的python脚本。
初赛
为了解释-m
标志,我们首先必须弄清楚一些术语。
首先,Python的主要组织单位称为模块。模块有两种形式之一:代码模块和包模块。代码模块是包含python可执行代码的任何文件。软件包模块是包含其他模块(代码模块或软件包模块)的目录。代码模块的最常见类型是*.py
文件,而软件包模块的最常见类型是包含__init__.py
文件的目录。
其次,可以通过两种不同的方式唯一标识所有模块:<modulename>
和<filename>
。模块通常由Python代码中的模块名称(例如import <modulename>
)和命令行上的文件名(例如)来标识python <filename>
。所有Python解释器都可以通过一组定义良好的规则将模块名转换为文件名。这些规则取决于sys.path
变量,因此可以通过更改此值来更改映射(有关如何完成此操作的更多信息,请参阅PEP 302)。
第三,所有模块(代码和程序包)都可以执行(这意味着与模块关联的代码将由Python解释器评估)。根据执行方法和模块类型的不同,对哪些代码进行评估以及何时修改可能会有所不同。例如,如果一个人通过执行一个包模块,python <filename>
那么<filename>/__init__.py
它将被评估,然后是<filename>/__main__.py
。另一方面,如果一个人通过执行相同的程序包模块,import <modulename>
那么__init__.py
将仅执行程序包。
的历史发展 -m
-m标志最初是在Python 2.4.1中引入的。最初,它的唯一目的是提供一种识别要执行的python模块的替代方法。也就是说,如果我们同时知道模块的<filename>
和<modulename>
,则以下两个命令是等效的:python <filename> <args>
和python -m <modulename> <args>
。另外,根据PEP 338,此迭代-m
仅适用于顶级模块名称(即,可以直接在sys.path上找到的模块,而无需任何中间包)。
随着完成PEP 338的-m
功能扩展到支持<modulename>
超出顶层modulenames表示。这意味着http.server
现在已经完全支持诸如这样的名称。此增强功能还意味着模块中的所有软件包现在都已加载(即,所有软件包__init__.py
文件均已评估)。
PEP 366-m
带来了最终的主要功能增强。通过此更新,不仅可以支持绝对导入,还可以支持显式相对导入。这是通过修改命令中命名模块的变量来实现的。-m
__package__
-m
用例
-m标志有两种值得注意的用例:
从命令行执行可能不知道其文件名的模块。该用例利用了Python解释器知道如何将模块名转换为文件名这一事实。当要从命令行运行stdlib模块或第三方模块时,这特别有利。例如,很少有人知道
http.server
模块的文件名,但大多数人确实知道其模块名,因此我们可以使用从命令行执行它python -m http.server
。要执行包含绝对导入的本地软件包,而无需安装它。PEP 338中详细介绍了该用例,并利用了将当前工作目录添加到
sys.path
而不是模块目录的事实。该用例与pip install -e .
在开发/编辑模式下安装软件包非常相似。
缺点
经过-m
多年的改进,它仍然存在一个主要缺点-它只能执行以python编写的代码模块(即* .py)。例如,如果-m
用于执行C编译代码模块,则会产生以下错误,No code object available for <modulename>
(请参见此处以获取更多详细信息)。
详细比较
通过python命令执行模块的效果(即python <filename>
):
sys.path
修改为包括最终目录<filename>
__name__
设定为'__main__'
__package__
设定为None
__init__.py
不评估任何软件包(包括其自身的软件包模块)__main__.py
评估包装模块;对代码进行代码模块评估。
通过import语句(即import <modulename>
)执行模块的影响:
sys.path
是不以任何方式修改__name__
设置为的绝对形式<modulename>
__package__
设置为中的直接父包<modulename>
__init__.py
针对所有软件包进行评估(包括针对软件包模块的评估)__main__.py
是不评价包模块; 对代码进行代码模块评估
通过-m标志(即python -m <modulename>
)执行模块的影响:
sys.path
修改为包括当前目录__name__
设定为'__main__'
__package__
设置为中的直接父包<modulename>
__init__.py
针对所有软件包进行评估(包括针对软件包模块的评估)__main__.py
评估包装模块;对代码进行代码模块评估
结论
从-m
最简单的角度来看,该标志是使用模块名而不是文件名从命令行执行python脚本的一种方法。另外,-m
提供了附加功能,结合了import
语句的功能(例如,支持显式相对导入和自动包__init__
评估)和python命令行的便利性。