你能给我解释一下打电话和打电话的区别吗
python -m mymod1 mymod2.py args
and
python mymod1.py mymod2.py args
在这两种情况下,似乎都调用了mymod1.py和sys. py。argv是
['mymod1.py', 'mymod2.py', 'args']
那么-m开关是干什么用的呢?
你能给我解释一下打电话和打电话的区别吗
python -m mymod1 mymod2.py args
and
python mymod1.py mymod2.py args
在这两种情况下,似乎都调用了mymod1.py和sys. py。argv是
['mymod1.py', 'mymod2.py', 'args']
那么-m开关是干什么用的呢?
当前回答
我只想提一个可能令人困惑的例子。
假设使用pip3安装一个包foo,其中包含一个bar模块。这意味着你可以执行python3 -m foo。Bar从任何目录。另一方面,你有一个这样的目录结构:
src
|
+-- foo
|
+-- __init__.py
|
+-- bar.py
你在src/。当你运行python -m foo。Bar,您运行的是Bar .py,而不是已安装的模块。然而,如果你正在调用python -m foo。Bar从任何其他目录,您正在使用已安装的模块。
如果使用python而不是python -m,这种行为当然不会发生,初学者可能会感到困惑。原因在于Python搜索模块的顺序。
其他回答
PEP 338的基本原理部分的第一行说:
Python 2.4增加了命令行开关-m,允许使用Python模块名称空间定位模块,以便作为脚本执行。鼓舞人心的例子是标准库模块,如pdb和profile, Python 2.4实现可以很好地实现这个有限的目的。
所以你可以用这种方式指定Python搜索路径中的任何模块,而不仅仅是当前目录中的文件。你是正确的,python mymod1.py mymod2.py args具有完全相同的效果。本提案部分范围的第一行规定:
在Python 2.4中,使用-m定位的模块会被执行,就好像它的文件名已经在命令行上提供了一样。
使用-m可以做更多的事情,比如处理作为包的一部分的模块,等等。这就是PEP 338的其余内容。阅读它以获得更多信息。
简而言之,'python -m'开关的最佳用例之一是当你想告诉python你想运行一个模块而不是执行一个.py文件时。
考虑这个例子:你在名为“venv”的文件中有一个Python脚本(没有“.py”文件扩展名)。如果你发出这个命令:
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试图执行一个名为“http”的文件。但没有找到。 因此,你想要发出相同的命令,但使用'-m'开关:
python -m http.server
这样Python就知道你想要模块的http。服务器不是文件。
尽管这个问题已经被问到并回答了好几次(例如,这里,这里,这里,这里,这里),但在我看来,没有现有的答案完全或简洁地抓住了-m标志的所有含义。因此,下面将尝试改进之前的内容。
介绍(TLDR)
-m标志可以做很多事情,但并不是所有的事情都需要。简而言之,它可以用于:(1)通过modulename而不是filename从命令行执行python代码(2)向sys. exe添加一个目录。在导入解析中使用的路径和(3)执行包含从命令行导入的相对python代码。
预赛
为了解释-m标志,我们首先需要解释一些术语。
Python的主要组织单位被称为模块。模块有两种类型:代码模块和包模块。代码模块是任何包含python可执行代码的文件。包模块是包含其他模块(代码模块或包模块)的目录。最常见的代码模块类型是*.py文件,而最常见的包模块类型是包含__init__.py文件的目录。
Python allows modules to be uniquely identified in two distinct 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 the sys.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).
所有模块(包括代码和包)都可以执行(即,与模块相关的代码将由Python解释器计算)。根据执行方法(和模块类型),什么代码被评估,以及什么时候被评估,可能会有相当大的变化。例如,如果通过python <filename>执行包模块,则将执行<filename>/__main__.py。另一方面,如果通过import <modulename>执行相同的包模块,则只会执行包的__init__.py。
-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> and python -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 on sys.path without any intervening package modules).
PEP 338完成后,-m特性被扩展到支持顶层以外的<modulename>表示。这意味着名称,如http。现在完全支持服务器。这个扩展还意味着除了modulename本身引用的模块之外,modulename中的每个父包现在都被计算(即,所有父包__init__.py文件都被计算)。
-m的最后一个主要特性增强来自PEP 366。通过这次升级,-m在执行模块时不仅可以支持绝对导入,还可以支持显式相对导入。这是通过改变-m来实现的,这样它就把__package__变量设置为给定模块名的父模块(除了它已经做的所有其他事情)。
用例
-m标志有两个值得注意的用例:
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 using python -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 using pip install -e . to install a package in develop/edit mode.
缺点
尽管这些年-m做了很多改进,但它仍然有一个主要的缺点——它只能执行用Python编写的模块(即*.py)。例如,如果-m用于执行C编译的代码模块,将产生以下错误,No code object available For <modulename>(参见这里了解更多详细信息)。
详细的比较
通过import语句(即import <modulename>)执行模块:
sys。路径不会以任何方式被修改 __name__被设置为<modulename>的绝对形式 __package__被设置为<modulename>中的直接父包 __init__.py对所有包(包括它自己的包模块)进行评估。 __main__.py不会为包模块评估;对代码模块进行评估
通过文件名(即python <filename>)的命令行执行模块:
sys。Path被修改为包含<filename>中的最终目录 __name__被设置为'__main__' __package__被设置为None __init__.py不会为任何包(包括它自己的包模块)求值 __main__.py为包模块评估;对代码模块进行评估。
通过modulename命令行执行模块(即python -m <modulename>):
sys。Path被修改为包含当前目录 __name__被设置为'__main__' __package__被设置为<modulename>中的直接父包 __init__.py对所有包(包括它自己的包模块)进行评估。 __main__.py为包模块评估;对代码模块进行评估
结论
简单地说,-m标志是一种通过使用模块名而不是文件名从命令行执行python脚本的方法。然而,-m的真正威力在于它能够将import语句的威力(例如,支持显式相对导入和自动包__init__求值)与命令行的便利性结合起来。
由于当你使用“python -m”时出现了这个问题,我只是想为那些喜欢模块化代码而不创建完整的python包或修改PYTHONPATH或sys. m的人添加一个快速参考。路径。
设置
让我们设置下面的文件结构
.
├── 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.
值得一提的是,这只适用于包有一个文件__main__.py,否则,这个包不能直接执行。
python -m some_package some_arguments
python解释器将在要执行的包路径中查找__main__.py文件。它相当于:
python path_to_package/__main__.py somearguments
它将执行以下内容:
if __name__ == "__main__":