你能解释一下调用以下两种方式的区别吗?
python -m mymod1 mymod2.py args
和
python mymod1.py mymod2.py args
看起来两种情况下都调用了mymod1.py
并使用了sys.argv
['mymod1.py', 'mymod2.py', 'args']
那么,-m
开关是用来做什么的?
你能解释一下调用以下两种方式的区别吗?
python -m mymod1 mymod2.py args
和
python mymod1.py mymod2.py args
看起来两种情况下都调用了mymod1.py
并使用了sys.argv
['mymod1.py', 'mymod2.py', 'args']
那么,-m
开关是用来做什么的?
-m
标志的所有含义。因此,以下内容将尝试改进之前的回答。-m
标志有很多功能,并非所有功能都会一直需要。简而言之,它可以用于:(1)通过模块名而不是文件名在命令行上执行Python代码,(2)将目录添加到sys.path
以供import
解析使用,以及(3)在命令行上执行包含相对导入的Python代码。-m
标志,我们首先需要解释一些术语。*.py
文件,而最常见的包模块类型是包含__init__.py
文件的目录。import <模块名>
),而在命令行中通过文件名来标识模块(例如,python <文件名>
)。所有的Python解释器都能够按照相同的几个明确定义的规则将模块名转换为文件名。这些规则依赖于sys.path
变量。通过修改这个变量,可以改变Python将模块名解析为文件名的方式(有关如何实现这一点的更多信息,请参阅PEP 302)。python <filename>
执行一个包模块,那么将执行<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
上找到的模块,而不需要任何中间包模块)。
-m
功能得到了扩展,以支持顶级之外的<modulename>
表示。这意味着像http.server
这样的名称现在得到了完全支持。这个扩展还意味着modulename中的每个父包都会被评估(即,所有父包的__init__.py
文件都会被评估),除了modulename本身引用的模块。
-m
的最后一个重要功能增强是通过PEP 366实现的。通过这个升级,-m
不仅可以支持绝对导入,还可以在执行模块时支持显式相对导入。这是通过改变-m
来设置__package__
变量为给定modulename的父模块(除了它已经做的其他一切)来实现的。
-m
标志有两个值得注意的用例:
http.server
模块的文件名,但大多数人知道它的模块名,所以我们可以使用python -m http.server
从命令行执行它。sys.path
而不是模块目录的事实。这种用法与使用pip install -e .
以开发/编辑模式安装包非常相似。尽管多年来对-m
进行了许多改进,但它仍然有一个主要缺点——它只能执行用Python编写的模块(即*.py
)。例如,如果使用-m
来执行一个C编译的代码模块,将会产生以下错误:No code object available for <modulename>
(更多详细信息请参见here)。
通过import语句执行模块(即import <modulename>
):
sys.path
在任何方式下都不会被修改__name__
被设置为 <modulename>
的绝对形式__package__
被设置为 <modulename>
的直接父包__init__.py
__main__.py
;该代码会被评估为代码模块通过命令行使用文件名执行模块(例如,python <filename>
):
sys.path
被修改以包含 <filename>
中的最终目录__name__
被设置为 '__main__'
__package__
被设置为 None
__init__.py
不会被评估为任何包(包括其自身的包模块)__main__.py
会被评估为包模块;代码会被评估为代码模块。通过命令行使用模块执行 (例如,python -m <modulename>
):
sys.path
被修改以包括当前目录__name__
被设置为 '__main__'
__package__
被设置为 <modulename>
的直接父包__init__.py
评估__main__.py
评估;对代码模块进行代码评估-m
标志最简单的作用是通过使用模块名而不是文件名,在命令行上执行 Python 脚本的一种方式。然而,-m
的真正威力在于它能够将 import
语句的功能(例如,支持显式相对导入和自动包 __init__
评估)与命令行的便利性结合起来。
python -m packagename
调用包的方法,就像这里提到的一样:https://dev59.com/Dmsz5IYBdhLWcg3w3bxb#53772635 - variablepython <filename>
执行一个包模块,则会先评估 <filename>/__init__.py
,然后是 <filename>/__main__.py.
”<dirname>
?如果是这样的话,只有 <dirname>/__main__.py
会被执行。__package__
为“”。“Python foo
”其中foo是一个包。 - figs_and_nutspython mymod1.py mymod2.py args
具有完全相同的效果。 Scope of this proposal
部分的第一行状态:-m
的用法是python -m SimpleHTTPServer
。当我需要分享一些文件但不想使用USB闪存驱动器时,这个方法非常方便。 - arifwnpython -m http.server
即可,这仍然很棒! - Kit Roedpython -m package.subpackage.module
命令来使用正常的解析机制,不需要指定精确的 .py
文件路径。
2)从被运行的模块中进行相对导入是可能的,无需任何变通方法,因为它所在的包会被加载。
3)绝对导入将基于你当前的目录,而不是 .py
文件所在的目录(如果脚本位于 /path/to/my/script.py
,则 sys.path
的开头为'',而不是/path/to/my
)。 - clacke__main__.py
文件的模块。大多数模块都没有这个文件,会出现错误,例如python -m sys 'print(sys.version)'
失败并显示python: No code object available for sys
。建议在答案中明确说明这一点。 - smci值得一提的是,只有当包中含有文件__main__.py
时,这才有效。否则,该包无法直接执行。
python -m some_package some_arguments
Python解释器会在包路径中查找__main__.py
文件并执行。这相当于:
python path_to_package/__main__.py somearguments
执行此代码后,将会执行该内容:
if __name__ == "__main__":
src
|
+-- foo
|
+-- __init__.py
|
+-- bar.py
src/
目录。当你运行 python -m foo.bar
时,你会运行 bar.py
文件,而不是安装的模块。然而,如果你从任何其他目录调用 python -m foo.bar
,那么你将使用已安装的模块。python
而不是 python -m
,则不会发生这种情况。python venv
然后,Python将在当前目录中执行“venv”文件。但是,如果您想使用“python venv”模块创建新的虚拟环境,则应运行:
python -m venv
在这种情况下,Python将运行“venv”模块,而不是文件“venv”。
另一个例子,如果您想运行Pyhton的内置本地http服务器并发出命令:
python http.server
你会得到一个错误,例如:
python: can't open file '/home/user/http.server': [Errno 2] No such file or directory
python -m http.server
这样Python就知道你想要的是模块'http.server'而不是文件。
由于在谷歌上搜索“使用'python -m'”时会出现此问题,因此我想为那些喜欢模块化代码但不想创建完整的Python包或每次修改PYTHONPATH
或sys.path
的人添加一个快速参考。
让我们设置以下文件结构
.
├── f1
│ ├── f2
│ │ ├── __init__.py
│ │ └── test2.py
│ ├── __init__.py
│ └── test1.py
└── test.py
让当前路径为m1
。
python -m
代替python ./*
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 do
python -m f1.test1
and not
python ./f1/test1.py
When using the module method, the sys.path
in test1.py
(when that is run) is m1
. When using the ./
(relative file) method, the path is m1/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 to m1
is stored (as PYTHONPATH
).
If we want to run deeply nested "modules", we can still use .
(just as we do in import
statements).
# This can be done
python -m f1.f2.test2
And in test2.py
, we can do from 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.
python -m f1.f2.test2
When we do that, the ./f1/__init__.py
is called, followed by ./f1/f2/__init__.py
.
-m
似乎在默认库路径中搜索mymod1
。例如:python -m SimpleHTTPServer
可以工作,而python SimpleHTTPServer
会失败并显示can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory
。 - Basj