使用`python -m pip`代替`pip`有什么效果?[副本]

0ve6wy6x  于 2023-05-08  发布在  Python
关注(0)|答案(8)|浏览(176)

此问题已在此处有答案

What's the difference between "pip install" and "python -m pip install"?(3个答案)
What is the purpose of the -m switch?(6个答案)
4天前关闭。
当我使用python -m pip install <package>时,它与仅使用pip install <package>有什么不同?同样,为什么要编写python -m pip install --upgrade pip来升级Pip,而不是只写pip install --upgrade pip

zpqajqem

zpqajqem1#

考虑以下场景。
你安装了三个版本的Python:

  • Python 3.7
  • Python 3.8
  • Python 3.9

您的“默认”版本是3.8。这是第一个出现在你的 * 路径 *。因此,当您在shell中键入python3(Linux或Mac)或python(Windows)时,您将启动3.8解释器,因为这是遍历路径时找到的第一个Python可执行文件。
假设你开始了一个新的项目,你想要使用Python 3.9。创建一个名为.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将启动3.9解释器。

但是,如果你输入

pip install <some-package>

pip是什么版本?它是否是默认版本的pip,即Python 3.8,还是虚拟环境中的Python版本?
一个简单的方法来解决这个模糊性是简单地使用

python -m pip install <some-package>

-m标志确保您正在使用绑定到活动Python可执行文件的pip。
最好始终使用-m,即使您只安装了一个用于创建虚拟环境的Python全局版本。

回复路径

所谓的 path 是系统搜索可执行文件的目录列表。当您键入一个命令(如python)时,此列表将从第一个目录遍历到最后一个目录,搜索与您键入的命令匹配的文件名。
如果找到文件名/命令,则执行匹配的文件,而不考虑以后可能的匹配。如果没有匹配,则得到Command not found或其变体。这种行为是设计出来的。
在UNIX系统上,path环境变量称为$PATH,而在Windows系统上,它被称为%PATH%

更多关于-m-flag的一般注解(Dec. 2022年)

大多数人看到这可能会希望上面给出的解释与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 some_module.py

但是对于Python标准库中的模块,这将不起作用。Python文档中的示例使用timeitpip的工作原理相同):

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__"子句。

python3 -m timeit -s 'print("hello")'

这和预期的一样。
timeit模块的if __name__ == "__main__"块的源代码可以在here中找到。

798qvoo8

798qvoo82#

Python Docs:
因为参数是一个模块名,所以不能给予文件扩展名(.py)。module-name应该是一个有效的Python模块名称,但实现可能并不总是强制执行此名称(例如它可能允许您使用包含连字符的名称)。
包名称也是允许的。当提供了一个包名而不是一个普通的模块时,解释器将执行<pkg>.__main__作为主模块。这种行为有意类似于作为脚本参数传递给解释器的目录和zip文件的处理。

u5rb5r59

u5rb5r593#

如果键入python --help
你得到

// More flags above
-m mod : run library module as a script (terminates option list)
// and more flags below

如果您使用command --helpman command,终端中的许多内容将向您展示如何使用它

hgc7kmma

hgc7kmma4#

-m代表module-name
Command line and environment
python [-bBdEhiIOqsSuvVWx?] [-c命令|-m模块名称|脚本|- ] [args]

92vpleto

92vpleto5#

-m与命令行上的python语句一起使用时,后跟<module_name>,则它使模块能够作为可执行文件执行。
您可以参考python文档,或者运行python --help

eivgtgni

eivgtgni6#

这实际上是一个有趣的问题,所以让我们在顶部评论中探索由@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 module”是不一样的。

**理论上很简单-它加载python并导入模块,而不是将代码转储到__main__中。这是一个不同的导入系统,其行为不同。其中一些更改不是故意的,只是在实施后才发现。Python的导入是一团乱,被搞混是可以的。

x33g5p2x

x33g5p2x7#

令人惊讶的是,当有些人说这个问题太简单而不值得费心时,这是如此难以回答。
据我所知,实际用途是当您不在目录中时,可以使用点表示法运行脚本。
可以运行python -m path.to.my.happy.place
而不是在path/to/my/happy中运行python place.py

owfi6suc

owfi6suc8#

如果你安装了多个版本的python,你想升级pip pip install --upgrade pip,你怎么知道哪个python版本会受到影响?它取决于shell的路径变量。在这种情况下,您也可能会收到警告。为了避免这种混淆,使用-m,然后在变量sys.path中查找。这是-m的另一个优点。

# importing module
import sys
  
# printing all directories for 
# interpreter to search
sys.path

相关问题