-m 开关的用途是什么?
之间的区别吗?
python -m mymod1 mymod2.py args
你能向我解释一下调用和
python mymod1.py mymod2.py args
似乎在这两种情况下都调用了 mymod1.py
和 sys.argv
['mymod1.py', 'mymod2.py', 'args']
那么 -m 是什么?
切换为?
Could you explain to me what the difference is between calling
python -m mymod1 mymod2.py args
and
python mymod1.py mymod2.py args
It seems in both cases mymod1.py
is called and sys.argv
is
['mymod1.py', 'mymod2.py', 'args']
So what is the -m
switch for?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
尽管这个问题已被多次提出和回答(例如,此处,这里,此处和此处 ),在我看来,没有现有的答案能够完全或简洁地捕获
-m
标志的所有含义。因此,下文将尝试在之前的基础上进行改进。简介 (TLDR)
-m
标志可以做很多事情,但并不是所有的事情都一直需要。简而言之,它可用于:(1) 通过模块名而不是文件名从命令行执行 python 代码 (2) 将目录添加到sys.path
以便在import
中使用code> 解析并 (3) 执行包含来自命令行的相对导入的 python 代码。预备知识
为了解释
-m
标志,我们首先需要解释一些术语。Python 的主要组织单元称为模块。模块有两种类型之一:代码模块和包模块。代码模块是包含 python 可执行代码的任何文件。包模块是包含其他模块(代码模块或包模块)的任何目录。最常见的代码模块类型是 *.py 文件,而最常见的包模块类型是包含 __init__.py 文件的目录。
Python 允许通过两种方式唯一标识模块:模块名和文件名。一般来说,模块由 Python 代码中的模块名(例如,
import
)和命令行上的文件名(例如,python
)来标识。 。所有 Python 解释器都能够通过遵循相同的几个明确定义的规则将模块名转换为文件名。这些规则取决于 sys.path 变量。通过更改此变量,可以更改 Python 将模块名解析为文件名的方式(有关如何完成此操作的更多信息,请参阅 PEP 302)。所有模块(代码和包)都可以执行(即与模块关联的代码将由Python解释器评估)。根据执行方法(和模块类型),评估哪些代码以及何时评估,可能会发生很大的变化。例如,如果通过执行相同的包模块,则只会执行包的
python
执行包模块,则/__main__.py
将被执行。另一方面,如果通过 import__init__.py
。-m
的历史发展-m
标志首次在 Python 2.4.1。最初它的唯一目的是提供一种识别要从命令行执行的 python 模块的替代方法。也就是说,如果我们知道模块的
和
,那么以下两个命令是等效的:python;
和python -m
。根据 PEP 338,此迭代的一个约束是-m
仅适用于顶级模块名称(即可以直接在sys.path
上找到的模块,无需任何中间包模块)。随着 PEP 338 的完成,
-m
功能已扩展为支持超出顶层的
表示。这意味着诸如http.server
之类的名称现在已得到完全支持。此扩展还意味着除了 modulename 本身引用的模块之外,现在还会评估 modulename 中的每个父包(即,评估所有父包 __init__.py 文件)。-m
的最终主要功能增强来自 PEP 366< /a>.通过此升级,-m
不仅能够支持绝对导入,还能够在执行模块时支持显式相对导入。这是通过更改-m
来实现的,以便将__package__
变量设置为给定模块名的父模块(除了它已经完成的其他所有操作之外)。用例
-m
标志有两个值得注意的用例:从命令行执行模块,而人们可能不知道其文件名。该用例利用了 Python 解释器知道如何将模块名转换为文件名的事实。当想要从命令行运行 stdlib 模块或第 3 方模块时,这是特别有利的。例如,很少有人知道
http.server
模块的文件名,但大多数人都知道它的模块名称,因此我们可以使用python -m http.server
从命令行执行它代码>.执行包含绝对或相对导入的本地包,而无需安装它。 PEP 338 中详细介绍了此用例 并利用当前工作目录被添加到
sys.path
而不是模块目录的事实。此用例与使用pip install -e .
在开发/编辑模式下安装软件包非常相似。缺点
尽管多年来对
-m
进行了所有增强,但它仍然有一个主要缺点 - 它只能执行用 Python 编写的模块(即*.py
)。例如,如果使用-m
执行 C 编译代码模块,则会产生以下错误:No code object available for
(请参阅此处了解更多详细信息)。详细比较
通过导入语句执行模块(即
import
):sys.path
不是以任何方式修改__name__
设置为
的绝对形式__package__
设置为< 中的直接父包;模块名称>
__init__.py
针对所有包(包括它自己的包模块)进行评估;__main__.py
不针对包模块进行评估;针对代码模块评估代码通过带有文件名的命令行执行模块(即
python
):sys.path
已修改将最终目录包含在
中__name__
设置为'__main__'
__package__
设置为 <代码>无__init__.py
不会针对任何包(包括它自己的包模块)进行评估;__main__.py
会针对包模块进行评估;代码针对代码模块进行评估。通过带有模块名称的命令行执行模块(即
python -m
):sys.path
被修改为包含当前目录__name__
设置为'__main__'
__package__
设置为
中的直接父包__init__.py
针对所有包(包括它自己的包模块)进行评估;__main__.py
针对包模块进行评估; 最简单的是,-m
标志结论
是一种使用模块名而不是文件名从命令行执行 python 脚本的方法。然而,
-m
的真正威力在于它能够结合import
语句的威力(例如,支持显式相对导入和自动包__init__< /code> 评估)与命令行的便利。
Despite this question having been asked and answered several times (e.g., here, here, here, and here), in my opinion no existing answer fully or concisely captures all the implications of the
-m
flag. Therefore, the following will attempt to improve on what has come before.Introduction (TLDR)
The
-m
flag does a lot of things, not all of which will be needed all the time. In short, it can be used to: (1) execute python code from the command line via modulename rather than filename (2) add a directory tosys.path
for use inimport
resolution and (3) execute python code that contains relative imports from the command line.Preliminaries
To explain the
-m
flag we first need to explain a little terminology.Python's primary organizational unit is known as a module. Modules come in one of two flavors: code modules and package modules. A code module is any file that contains python executable code. A package module is any directory that contains other modules (either code modules or package modules). The most common type of code module is a
*.py
file while the most common type of package module is a directory containing an__init__.py
file.Python allows modules to be uniquely identified in two ways: modulename and filename. In general, modules are identified by modulename in Python code (e.g.,
import <modulename>
) and by filename on the command line (e.g.,python <filename>
). All Python interpreters are able to convert modulenames to filenames by following the same few, well-defined rules. These rules hinge on thesys.path
variable. By altering this variable one can change how Python resolves modulenames into filenames (for more on how this is done see PEP 302).All modules (both code and package) can be executed (i.e., code associated with the module will be evaluated by the Python interpreter). Depending on the execution method (and module type) what code gets evaluated, and when, can change quite a bit. For example, if one executes a package module via
python <filename>
then<filename>/__main__.py
will be executed. On the other hand, if one executes that same package module viaimport <modulename>
then only the package's__init__.py
will be executed.Historical Development of
-m
The
-m
flag was first introduced in Python 2.4.1. Initially its only purpose was to provide an alternative means of identifying the python module to execute from the command line. That is, if we knew both the<filename>
and<modulename>
for a module then the following two commands were equivalent:python <filename> <args>
andpython -m <modulename> <args>
. One constraint with this iteration, according to PEP 338, was that-m
only worked with top level modulenames (i.e., modules that could be found directly onsys.path
without any intervening package modules).With the completion of PEP 338 the
-m
feature was extended to support<modulename>
representations beyond the top level. This meant names such ashttp.server
were now fully supported. This extension also meant that each parent package in modulename was now evaluated (i.e., all parent package__init__.py
files were evaluated) in addition to the module referenced by the modulename itself.The final major feature enhancement for
-m
came with PEP 366. With this upgrade-m
gained the ability to support not only absolute imports but also explicit relative imports when executing modules. This was achieved by changing-m
so that it set the__package__
variable to the parent module of the given modulename (in addition to everything else it already did).Use Cases
There are two notable use cases for the
-m
flag:To execute modules from the command line for which one may not know their filename. This use case takes advantage of the fact that the Python interpreter knows how to convert modulenames to filenames. This is particularly advantageous when one wants to run stdlib modules or 3rd-party module from the command line. For example, very few people know the filename for the
http.server
module but most people do know its modulename so we can execute it from the command line usingpython -m http.server
.To execute a local package containing absolute or relative imports without needing to install it. This use case is detailed in PEP 338 and leverages the fact that the current working directory is added to
sys.path
rather than the module's directory. This use case is very similar to usingpip install -e .
to install a package in develop/edit mode.Shortcomings
With all the enhancements made to
-m
over the years it still has one major shortcoming -- it can only execute modules written in Python (i.e.,*.py
). For example, if-m
is used to execute a C compiled code module the following error will be produced,No code object available for <modulename>
(see here for more details).Detailed Comparisons
Module execution via import statement (i.e.,
import <modulename>
):sys.path
is not modified in any way__name__
is set to the absolute form of<modulename>
__package__
is set to the immediate parent package in<modulename>
__init__.py
is evaluated for all packages (including its own for package modules)__main__.py
is not evaluated for package modules; the code is evaluated for code modulesModule execution via command line with filename (i.e.,
python <filename>
):sys.path
is modified to include the final directory in<filename>
__name__
is set to'__main__'
__package__
is set toNone
__init__.py
is not evaluated for any package (including its own for package modules)__main__.py
is evaluated for package modules; the code is evaluated for code modules.Module execution via command line with modulename (i.e.,
python -m <modulename>
):sys.path
is modified to include the current directory__name__
is set to'__main__'
__package__
is set to the immediate parent package in<modulename>
__init__.py
is evaluated for all packages (including its own for package modules)__main__.py
is evaluated for package modules; the code is evaluated for code modulesConclusion
The
-m
flag is, at its simplest, a means to execute python scripts from the command line by using modulenames rather than filenames. The real power of-m
, however, is in its ability to combine the power ofimport
statements (e.g., support for explicit relative imports and automatic package__init__
evaluation) with the convenience of the command line.PEP 338基本原理部分的第一行> 说:
所以你可以通过这种方式指定Python搜索路径中的任何模块,而不仅仅是当前目录中的文件。您是对的,
python mymod1.py mymod2.py args
具有完全相同的效果。此提案的范围
部分的第一行指出:使用
-m
可以实现更多功能,例如使用属于包一部分的模块等。这就是 PEP 338 其余部分的内容。阅读它以获取更多信息。The first line of the
Rationale
section of PEP 338 says:So you can specify any module in Python's search path this way, not just files in the current directory. You're correct that
python mymod1.py mymod2.py args
has exactly the same effect. The first line of theScope of this proposal
section states:With
-m
more is possible, like working with modules which are part of a package, etc. That's what the rest of PEP 338 is about. Read it for more info.值得一提的是只有当包中有文件
__main__.py
时才有效,否则该包无法直接执行。python解释器将在包路径中寻找
__main__.py
文件来执行。相当于:它将执行之后的内容:
It's worth mentioning this only works if the package has a file
__main__.py
Otherwise, this package can not be executed directly.The python interpreter will looking for a
__main__.py
file in the package path to execute. It's equivalent to:It will execute the content after:
我只想提一个可能令人困惑的案例。
假设您使用
pip3
安装包foo
,其中包含bar
模块。所以这意味着您可以从任何目录执行python3 -m foo.bar
。另一方面,您的目录结构如下:您位于
src/
。当您运行python -m foo.bar
时,您正在运行bar.py
,而不是已安装的模块。但是,如果您从任何其他目录调用 python -m foo.bar ,则您正在使用已安装的模块。如果您使用
python
而不是python -m
,这种行为肯定不会发生,并且可能会让初学者感到困惑。原因是 Python 搜索模块的顺序。I just want to mention one potentially confusing case.
Suppose you use
pip3
to install a packagefoo
, which contains abar
module. So this means you can executepython3 -m foo.bar
from any directory. On the other hand, you have a directory structure like this:You are at
src/
. When you runpython -m foo.bar
, you are running thebar.py
, instead of the installed module. However, if you are callingpython -m foo.bar
from any other directory, you are using the installed module.This behavior certainly doesn't happen if you are using
python
instead ofpython -m
, and can be confusing for beginners. The reason is the order how Python searches for modules.简而言之,“python -m”开关的最佳用例之一是当您想要告诉 Python 您想要运行模块而不是执行 .py 文件时。
考虑以下示例:名为“venv”的文件(不带“.py”文件扩展名)中有一个 Python 脚本。如果您发出此命令:
那么,Python 将执行当前目录中的“venv”文件。但是,如果您想使用“python venv”模块创建新的虚拟环境,则可以运行:
在这种情况下,Python 将运行“venv”模块,而不是“venv”文件。
另一个例子,如果你想运行 Pyhton 的内置本地 http 服务器并发出命令:
你会得到一个类似这样的错误:
那是因为 Python 试图执行一个名为“http.server”的文件,但没有找到它。
因此,您希望发出相同的命令,但使用“-m”开关:
以便 Python 知道您需要模块“http.server”而不是文件。
In short, one of the best use case for 'python -m' switch is when you want to tell Python that you want to run a module instead of executing a .py file.
Consider this example: you have a Python script in a file named 'venv' (without '.py' file extension). If you issue this command:
then, Python will excute the 'venv' file in the current directory. However, if instead you want to create a new virtual environment using the 'python venv' module, you would run:
in which case, Python will run the 'venv' module, not the file 'venv'.
Another example, if you want to run Pyhton's built-in local http server and issue the command:
you would get an error like:
That's because Python tried to execute a file called 'http.server' and didn't find it.
So instead, you want to issue the same command but with '-m' switch:
so that Python knows you want the module 'http.server' not the file.
由于当您搜索
Use of "python -m"
时会出现这个问题,我只是想为那些喜欢模块化代码而不创建完整的 Python 包 或 每次修改PYTHONPATH
或sys.path
。设置
让我们设置以下文件结构,
让当前路径为
m1
。使用
python -m
而不是python ./*
使用
.
限定的模块文件名称(因为它们现在被视为模块)。例如,要运行./f1/test1.py
中的内容,我们这样做而不是
当使用 module 方法时,
sys.path
是test1.py
(运行时)中的m1
。使用./
(相对文件)方法时,路径为m1/f1
。因此我们可以使用
-m
访问 m1 中的所有文件(并假设它是一个完整的 python 包)。这是因为m1
的路径已存储(作为PYTHONPATH
)。如果我们想运行深层嵌套的“模块”,我们仍然可以使用
。
(就像我们在import
语句中所做的那样)。在
test2.py
中,我们可以执行from f1.test1 import do_something
而无需使用任何 其中的路径噱头。每次我们以这种方式导入模块时,都会自动调用
__init__.py
。即使我们筑巢时也是如此。当我们这样做时,会调用
./f1/__init__.py
,然后调用./f1/f2/__init__.py
。Since this question comes up when you google
Use of "python -m"
, I just wanted to add a quick reference for those who like to modularize code without creating full python packages or modifyingPYTHONPATH
orsys.path
every time.Setup
Let's setup the following file structure
Let the present path be
m1
.Using
python -m
instead ofpython ./*
Use
.
qualified module names for the files (because they're being treated as modules now). For example, to run the contents in./f1/test1.py
, we doand not
When using the module method, the
sys.path
intest1.py
(when that is run) ism1
. When using the./
(relative file) method, the path ism1/f1
.So we can access all files in
m1
(and assume that it is a full python package) using-m
. This is because the path tom1
is stored (asPYTHONPATH
).If we want to run deeply nested "modules", we can still use
.
(just as we do inimport
statements).And in
test2.py
, we can dofrom f1.test1 import do_something
without using any path gimmicks in it.Every time we do module imports this way, the
__init__.py
is automatically called. This is true even when we're nesting.When we do that, the
./f1/__init__.py
is called, followed by./f1/f2/__init__.py
.TLDR:
-m
标志允许您从任何地方运行脚本(模块),只要 Python 可以找到它。更长的版本:
假设我们有一个脚本
my_script.py
。您必须从文件所在的目录运行
python my_script.py
。或者 -
python path/to/my_script.py
但是,您可以运行
python -m my_script
(即通过省略.py 按模块名称引用脚本
)从任何地方,只要Python能找到它!Python 搜索如下(不能 100% 确定顺序):
PythonXX\Lib
(标准库所在的位置,如os 或
random
PythonXX\Lib\site-packages
(全局安装的包所在的位置)要对其进行测试,请继续将“Hello World”脚本放置在 <代码>站点包或者在 PYTHONPATH 环境变量中设置其目录,您会发现可以从命令行的任何位置运行它
有关更多低级但重要的差异,请参阅其他答案。
TLDR:
The
-m
flag lets you run a script (module) from anywhere, as long as Python can find it.Longer version:
Assume we have a script
my_script.py
.You must run
python my_script.py
from the directory where the file is located.Alternatively -
python path/to/my_script.py
However, you can run
python -m my_script
(ie refer to the script by module name by omitting the.py
) from anywhere, as long as Python can find it!Python searches as follows (not 100% sure about the order):
PythonXX\Lib
(where the standard libraries live, likeos
orrandom
PythonXX\Lib\site-packages
(where globally installed packages live)To test it out, go ahead and place a "Hello World" script in either
site-packages
or set its directory in the PYTHONPATH env variable, and you will find that you can run it from anywhere on the command line.For more low-level but important differences, see other answers.