python -m pip install <package>中的-m是什么意思?或者在使用python -m pip install --upgrade pip升级pip时。仅运行“pip install“时有什么区别
python -m pip install <package>
python -m pip install --upgrade pip
t9aqgxwy1#
请考虑以下场景。您安装了三个版本的Python:
你的“默认”版本是3.8,它是出现在你的 path 中的第一个版本,因此,当你在shell中输入python3(Linux或Mac)或python(Windows)时,你将启动一个3.8解释器,因为这是在遍历你的路径时找到的第一个Python可执行文件。假设您正在启动一个新的项目,您希望在其中使用Python 3.9,您创建了一个名为.venv的虚拟环境并激活它。
python3
python
.venv
python3.9 -m venv .venv # "py -3.9" on Windows
source .venv/bin/activate # ".venv\Scripts\activate" on Windows
现在我们已经使用Python 3.9激活了虚拟环境,在shell中输入python将启动Python 3.9解释器。
但是,如果您键入
pip install <some-package>
那么pip使用的是什么版本?是默认版本的pip,即Python 3.8,还是虚拟环境中的Python版本?避免这种模糊性的一个简单方法就是使用
pip
python -m pip install <some-package>
-m标志确保您使用的是绑定到活动Python可执行文件的pip。始终使用-m是一个很好的实践,即使您只安装了一个全局版本的Python来创建虚拟环境。
-m
所谓的 path 是系统搜索可执行文件的目录列表,当你键入一个命令,比如python,这个列表会从第一个目录遍历到最后一个目录,搜索与你键入的命令相匹配的文件名。如果找到文件名/命令,则执行匹配的文件,而不考虑以后可能的匹配。如果没有匹配,则获得Command not found或其变体。此行为是设计的。在UNIX系统上,路径环境变量称为$PATH,而在Windows系统上则称为%PATH%
Command not found
$PATH
%PATH%
大多数人看到这篇文章可能会想知道上面pip的解释,但从更普遍的意义上讲,当使用python -m some_module时,-m标志会使Python将some_module作为脚本执行,这在docs中有说明,但如果没有一些基本知识,可能很难理解。
python -m some_module
some_module
“作为脚本运行”是什么意思?
在Python中,模块some_module通常被导入到另一个Python文件中,并且在导入文件的顶部有一个import some_module语句。这样就可以在导入文件中使用some_module中定义的函数、类和变量。要将some_module作为脚本执行而不是导入它,您将在文件中定义一个if __name__ == "__main__"块。在命令行上运行python some_module.py时,将执行此块。这很有用,因为您不希望在导入到其他文件时运行此代码块,但您确实希望它在从命令行调用时运行。对于项目内部的模块,这个脚本/模块构造应该按原样运行,因为Python在从终端运行时会从工作目录中找到模块:
import some_module
if __name__ == "__main__"
python some_module.py
但是对于Python标准库中的模块来说,这是行不通的,Python文档中的例子使用了timeit(pip的工作原理是一样的):
timeit
python3 timeit -s 'print("hello")' # 'python timeit.py ...' fails as well
这将返回错误:"python: can't open file '/home/<username>/timeit': [Errno 2] No such file or directory"添加-m标志告诉Python在path中查找timeit.py,并从文件中执行if __name__ == "__main__"子句。
"python: can't open file '/home/<username>/timeit': [Errno 2] No such file or directory"
timeit.py
python3 -m timeit -s 'print("hello")'
这按预期工作。timeit模块的if __name__ == "__main__"块的源代码可以在here中找到。
8ulbf1ek2#
来自Python文档:因为参数是一个模块名,所以不能给予文件扩展名(.py)。module-name应该是一个有效的Python模块名,但是实现可能并不总是强制这样(例如,它可能允许你使用一个包含连字符的名称)。包名也是允许的。当提供包名而不是正常的模块时,解释器会将<pkg>.__main__作为主模块执行。这种行为有意类似于作为脚本参数传递给解释器的目录和zip文件的处理。
module-name
<pkg>.__main__
eblbsuwk3#
-m代表module-name。从Command line and environment开始:python [-bBdEhiIOqsSuvVWx?] [-c命令|-m模块名称|脚本|- ] [参数]
0ve6wy6x4#
如果您键入python --help你得到
python --help
// More flags above -m mod : run library module as a script (terminates option list) // and more flags below
如果您使用command --help或man command,终端中的许多内容将向您展示如何使用它
command --help
man command
fykwrbwg5#
当-m与命令行上的python语句一起使用,后跟<module_name>时,它使模块能够作为可执行文件执行。您可以参考python文档以获得相同的信息,或者运行python --help
<module_name>
yb3bgrhw6#
这其实是一个很有趣的问题,所以让我们来探讨一下顶部评论中@jedwards链接的pep 338。-m标志最初的用途比较简单--将模块名转换为脚本名,在Python 2.4中,行为是:
the command line is effectively reinterpreted from python <options> -m <module> <args> to python <options> <filename> <args>.
这看起来不是很有用,但这就是它当时所做的。Pep 338进一步扩展了这种行为。提出的语义相当简单[原文如此]:如果使用-m来执行模块,则在根据顶层模块的语义执行模块之前,使用PEP 302导入机制来定位模块并检索其编译代码。它进一步解释了python将识别模块来自哪个包,使用标准过程导入那个包,然后运行模块.据我所知,调用“python3 -m package.module”与调用:
python3 from package import module
-m标志将以__file__而不是__main__的身份运行模块。它还将本地目录插入sys.path而不是脚本目录。因此,它中断了相对导入,尽管这不是有意的。因此,作者建议始终使用绝对导入,这也取决于您如何调用它--“python3 -m package.module”与“python3 -m模块”。
__file__
__main__
**理论上很简单--它加载python并导入模块,而不是将代码转储到__main__中。**实际上,这有很多影响。这是一个不同的导入系统,行为也不同。其中一些更改不是故意的,只是在实现后才发现。Python的导入很混乱,混淆是正常的。
t3irkdon7#
令人惊讶的是,这是如此难以回答,当有些人说,这个问题太简单,麻烦。据我所知,实际用途是当您不在目录中时,可以使用点标记来运行脚本。您可以运行python -m path.to.my.happy.place而不是在path/to/my/happy中运行python place.py
python -m path.to.my.happy.place
path/to/my/happy
python place.py
u1ehiz5o8#
如果你安装了多个版本的python,并且你想升级pip pip install --upgrade pip,你怎么知道哪个版本的python会受到影响?这取决于shell的路径变量。在这种情况下,你也可能会收到警告。为了避免这种混淆,使用-m,然后它会在变量sys.path中查找。这是-m的另一个优点。
pip install --upgrade pip
# importing module import sys # printing all directories for # interpreter to search sys.path
8条答案
按热度按时间t9aqgxwy1#
请考虑以下场景。
您安装了三个版本的Python:
你的“默认”版本是3.8,它是出现在你的 path 中的第一个版本,因此,当你在shell中输入
python3
(Linux或Mac)或python
(Windows)时,你将启动一个3.8解释器,因为这是在遍历你的路径时找到的第一个Python可执行文件。假设您正在启动一个新的项目,您希望在其中使用Python 3.9,您创建了一个名为
.venv
的虚拟环境并激活它。现在我们已经使用Python 3.9激活了虚拟环境,在shell中输入
python
将启动Python 3.9解释器。但是,如果您键入
那么
pip
使用的是什么版本?是默认版本的pip,即Python 3.8,还是虚拟环境中的Python版本?避免这种模糊性的一个简单方法就是使用
-m
标志确保您使用的是绑定到活动Python可执行文件的pip。始终使用
-m
是一个很好的实践,即使您只安装了一个全局版本的Python来创建虚拟环境。参考路径
所谓的 path 是系统搜索可执行文件的目录列表,当你键入一个命令,比如
python
,这个列表会从第一个目录遍历到最后一个目录,搜索与你键入的命令相匹配的文件名。如果找到文件名/命令,则执行匹配的文件,而不考虑以后可能的匹配。如果没有匹配,则获得
Command not found
或其变体。此行为是设计的。在UNIX系统上,路径环境变量称为
$PATH
,而在Windows系统上则称为%PATH%
关于
-m
-flag的更多一般性注解(2022年12月)大多数人看到这篇文章可能会想知道上面pip的解释,但从更普遍的意义上讲,当使用
python -m some_module
时,-m
标志会使Python将some_module
作为脚本执行,这在docs中有说明,但如果没有一些基本知识,可能很难理解。“作为脚本运行”是什么意思?
在Python中,模块
some_module
通常被导入到另一个Python文件中,并且在导入文件的顶部有一个import some_module
语句。这样就可以在导入文件中使用some_module
中定义的函数、类和变量。要将some_module
作为脚本执行而不是导入它,您将在文件中定义一个if __name__ == "__main__"
块。在命令行上运行python some_module.py
时,将执行此块。这很有用,因为您不希望在导入到其他文件时运行此代码块,但您确实希望它在从命令行调用时运行。对于项目内部的模块,这个脚本/模块构造应该按原样运行,因为Python在从终端运行时会从工作目录中找到模块:
但是对于Python标准库中的模块来说,这是行不通的,Python文档中的例子使用了
timeit
(pip
的工作原理是一样的):这将返回错误:
"python: can't open file '/home/<username>/timeit': [Errno 2] No such file or directory"
添加
-m
标志告诉Python在path中查找timeit.py
,并从文件中执行if __name__ == "__main__"
子句。这按预期工作。
timeit模块的
if __name__ == "__main__"
块的源代码可以在here中找到。8ulbf1ek2#
来自Python文档:
因为参数是一个模块名,所以不能给予文件扩展名(.py)。
module-name
应该是一个有效的Python模块名,但是实现可能并不总是强制这样(例如,它可能允许你使用一个包含连字符的名称)。包名也是允许的。当提供包名而不是正常的模块时,解释器会将
<pkg>.__main__
作为主模块执行。这种行为有意类似于作为脚本参数传递给解释器的目录和zip文件的处理。eblbsuwk3#
-m
代表module-name
。从Command line and environment开始:
python [-bBdEhiIOqsSuvVWx?] [-c命令|-m模块名称|脚本|- ] [参数]
0ve6wy6x4#
如果您键入
python --help
你得到
如果您使用
command --help
或man command
,终端中的许多内容将向您展示如何使用它fykwrbwg5#
当
-m
与命令行上的python
语句一起使用,后跟<module_name>
时,它使模块能够作为可执行文件执行。您可以参考python文档以获得相同的信息,或者运行
python --help
yb3bgrhw6#
这其实是一个很有趣的问题,所以让我们来探讨一下顶部评论中@jedwards链接的pep 338。
-m标志最初的用途比较简单--将模块名转换为脚本名,在Python 2.4中,行为是:
这看起来不是很有用,但这就是它当时所做的。Pep 338进一步扩展了这种行为。
提出的语义相当简单[原文如此]:如果使用-m来执行模块,则在根据顶层模块的语义执行模块之前,使用PEP 302导入机制来定位模块并检索其编译代码。
它进一步解释了python将识别模块来自哪个包,使用标准过程导入那个包,然后运行模块.据我所知,调用“python3 -m package.module”与调用:
-m标志将以
__file__
而不是__main__
的身份运行模块。它还将本地目录插入sys.path而不是脚本目录。因此,它中断了相对导入,尽管这不是有意的。因此,作者建议始终使用绝对导入,这也取决于您如何调用它--“python3 -m package.module”与“python3 -m模块”。**理论上很简单--它加载python并导入模块,而不是将代码转储到
__main__
中。**实际上,这有很多影响。这是一个不同的导入系统,行为也不同。其中一些更改不是故意的,只是在实现后才发现。Python的导入很混乱,混淆是正常的。t3irkdon7#
令人惊讶的是,这是如此难以回答,当有些人说,这个问题太简单,麻烦。
据我所知,实际用途是当您不在目录中时,可以使用点标记来运行脚本。
您可以运行
python -m path.to.my.happy.place
而不是在
path/to/my/happy
中运行python place.py
u1ehiz5o8#
如果你安装了多个版本的python,并且你想升级pip
pip install --upgrade pip
,你怎么知道哪个版本的python会受到影响?这取决于shell的路径变量。在这种情况下,你也可能会收到警告。为了避免这种混淆,使用-m
,然后它会在变量sys.path中查找。这是-m
的另一个优点。