如何在代码中安装Python模块?

496

我需要在我的脚本中直接从PyPI安装一个包。

是否有某个模块或distutils (distribute, pip等)功能,允许我只需执行类似于pypi.install('requests')的命令就能将requests安装到我的虚拟环境中?


4
为什么不在你自己的包的 setup.py 中将相关模块定义为依赖关系? - user2665694
8
你知道...实际上应该这样做...但你总是可以使用os.system("pip install blah"),但你可能需要sudo权限...最好将其作为依赖项在你的setup.py中设置。 - Joran Beasley
2
@chuwy https://dev59.com/Gmct5IYBdhLWcg3wHZ9q#50255019 <= 这个。pip._internal 不是为了可导入而设计的,当在另一个程序中导入时,它可能会做绝对随机的事情。 - Antti Haapala -- Слава Україні
2
@Antti是正确的。目前最佳答案在这里。当前接受的答案不建议使用,容易出错,正如_pip_用户指南中“从程序中使用pip”的部分所明确说明的那样。巧合的是,这也是正在由_pip_的维护者们讨论的问题 - sinoroc
3
好的,我已经修改了。个人而言,我不喜欢这两种解决方案,但是最近我离 Python 很远,所以我相信你的意见。 - chuwy
显示剩余5条评论
13个回答

570

从脚本中安装软件包的官方推荐方式是通过调用 pip 的命令行界面来进行子进程。 这里介绍的大多数其他方法都不受 pip 支持。此外,自 pip v10 以来,所有代码都已移动到 pip._internal 中,以准确地向用户表明不允许使用 pip 进行编程。

使用 sys.executable 来确保您将调用与当前运行时相关联的相同的 pip

import subprocess
import sys

def install(package):
    subprocess.check_call([sys.executable, "-m", "pip", "install", package])

4
这种方法的一个问题是,对于Windows上的新手用户来说,Python和pip不一定在他们的PATH路径中,因此一个.py文件可以通过双击打开非常方便,而“pip install xxx”这样的命令可能会很棘手。 - jdpipe
14
CalledProcessError: 命令 '['C:\ProgramData\Anaconda3\pythonw.exe', '-m', 'pip', 'install', 'googleapiclient']' 返回非零的退出状态 1。 - parvij
2
我正在尝试使用这种方法,但我的Python是从另一个可执行文件嵌入/启动的,因此"sys.executable"不能返回正确的路径。是否有其他替代方案适用于由其他进程启动的Python? - user441669
奇怪的事情是,我需要重新运行安装该模块的脚本,以便它能被识别。 - BND
10
注意,自3.5版本起,现在建议使用subprocess.run(..., check=True) - Brian
显示剩余2条评论

436

你也可以使用类似以下的方式:

import pip

def install(package):
    if hasattr(pip, 'main'):
        pip.main(['install', package])
    else:
        pip._internal.main(['install', package])

# Example
if __name__ == '__main__':
    install('argh')

3
你可以像在命令行中一样向 pip.main() 传递选项(但每个选项应作为列表中的单独条目,而不是单个字符串)。要指定所需包的版本,请使用与命令行相同的方式。例如:pip.main(['install', 'pip==7.1.0']) - Kaos
3
请参考https://dev59.com/6mw15IYBdhLWcg3wtNuO,其中介绍了如何处理安装失败的情况。 - Myer
31
你可以使用 from pip._internal import main as pipmain,然后像废弃的 pip.main() 一样使用 pipmain()。参见 https://dev59.com/-1cQ5IYBdhLWcg3wD_ho。 - 3pitt
19
现在已经不推荐使用了。 - Morse
13
这个东西已经被废弃了,而且不再建议使用。请查看 https://pip.pypa.io/en/latest/user_guide/#using-pip-from-your-program。 - nbk
显示剩余19条评论

91

如果您想使用 pip 安装所需的包并在安装后导入它,请使用此代码:

要使用pip安装所需的软件包并在安装后导入它,请使用以下代码:

def install_and_import(package):
    import importlib
    try:
        importlib.import_module(package)
    except ImportError:
        import pip
        pip.main(['install', package])
    finally:
        globals()[package] = importlib.import_module(package)


install_and_import('transliterate')

如果您将软件包安装为用户,可能会遇到无法导入软件包的问题。请参见如何刷新sys.path? 以获取更多信息。


4
有没有想过如何在Python 3上实现?执行imp.reload(site)时出现了RuntimeError: dictionary changed size during iteration的错误提示。 - kgadek
这个安装程序把包安装在哪里?我执行完这个操作后,无法使用 pip uninstall <package_name> 命令卸载它。虽然我仍然可以使用 pip.main 命令卸载它,但我想知道这个包被安装在哪里了? - Ishan Khare
我很好奇。如果我这样做:pip install requests[security],它会正常工作吗?我不确定它是否会正确定义全局变量。 - Fallenreaper
7
过时了。pip.main 不再有效。https://pip.pypa.io/en/latest/user_guide/#using-pip-from-your-program - wim
1
在函数内部导入模块是否真的会导入到主命名空间,还是只会导入到install_and_import函数的命名空间中? - sh37211
如果安装和重新加载脚本调用另一个执行导入的脚本,为什么这个不起作用? - CIsForCookies

44
这应该有效:
import subprocess

def install(name):
    subprocess.call([sys.executable, '-m', 'pip', 'install', name])

2
是的,它肯定可以工作。但我认为可能有更优雅的方式;) 我会等一下,也许会有更好的方法。 - chuwy
3
@Downvoter:我的回答到底有什么问题?这个答案包含了OP想要的一切,甚至没有使用shell。 - quantum
15
这取决于正确版本的pip在路径中是否排在第一位。如果用户运行的是替代的Python安装程序,pip将安装到第一个程序而不是当前程序中。上述导入方法会安装到正确的位置。我仍然点赞以抵消反对票。 - GaryBishop
7
根据脚本运行的情况,你可能无法调用正确的pip。 - Natim
11
调用[sys.executable, '-m', 'pip', 'install', name]确保获取“正确”的pip。 - wim
显示剩余6条评论

38

我对Aaron的回答进行了一些异常处理。

import subprocess
import sys

try:
    import pandas as pd
except ImportError:
    subprocess.check_call([sys.executable, "-m", "pip", "install", 'pandas'])
finally:
    import pandas as pd

2
很好的subprocess和pip实现,比这里大多数解决方案都要好。 - Shantanu Bedajna
4
你没有检查subprocess.call的返回值,所以代码可能会失败。 - Antti Haapala -- Слава Україні
1
为什么要使用subprocess.check_call而不是subprocess.call - Coddy
好的,运行“import pandas as pd”没有问题,但是...从逻辑上讲,这不是很丑吗? - Daniel Bandeira
1
很好,不过我会在安装except代码块后再进行最后一次导入。 - AD - Stop Putin -

29

为了安装多个软件包,我正在使用一个带有以下代码的setup.py文件:

import sys
import subprocess
import pkg_resources

required  = {'numpy', 'pandas', '<etc>'} 
installed = {pkg.key for pkg in pkg_resources.working_set}
missing   = required - installed

if missing:
    # implement pip as a subprocess:
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', *missing])

2
*missing 前面的星号用于解包由变量名 missing 表示的集合。另请参阅:理解 Python 中的星号(*) - Serge Stroobandt

12

使用:

import os
os.system('pip install requests')

我尝试了上述方法,作为一个临时解决方案,而不是更改Docker文件


相比其他答案,这太容易而且简单易懂了,特别适合初学者。非常感谢! - Shubham Garg

8
如果您想要一个更高效的答案,扩展了subprocess.check_call。您可以先使用pkg_resources检查需求是否已经满足。

这适用于不同的需求规范,非常好。例如,>===

import sys
import subprocess
import pkg_resources
from pkg_resources import DistributionNotFound, VersionConflict

def should_install_requirement(requirement):
    should_install = False
    try:
        pkg_resources.require(requirement)
    except (DistributionNotFound, VersionConflict):
        should_install = True
    return should_install


def install_packages(requirement_list):
    try:
        requirements = [
            requirement
            for requirement in requirement_list
            if should_install_requirement(requirement)
        ]
        if len(requirements) > 0:
            subprocess.check_call([sys.executable, "-m", "pip", "install", *requirements])
        else:
            print("Requirements already satisfied.")

    except Exception as e:
        print(e)

示例用法:

requirement_list = ['requests', 'httpx==0.18.2']
install_packages(requirement_list)

Demo

相关信息:Stack Overflow问题:58612272

太棒了!作为一个小改进,我们来看看: subprocess.check_call( [sys.executable, "-m", "pip", "install", *requirements]) else: print("要求已经满足。") - Simon Provost
动画无法阅读(但如果在单独的选项卡或窗口中打开,则可以正常工作)。 - Peter Mortensen

7

在您自己的软件包的setup.py文件中,使用"install_requires"选项定义依赖模块。

如果您的软件包需要生成一些控制台脚本,则可以使用"console_scripts"入口点来生成一个包装器脚本,该脚本将放置在'bin'文件夹中(例如您的虚拟环境)。


1
这是正确的答案,也是管理Python项目依赖项的唯一明智方法。它可以与virtualenv、Fabric、buildout等工具配合使用。虽然@xiaomao描述的方法确实回答了OP所问的问题,但纯属疯狂。 - Lukas Graf
9
虽然这是正确的建议,但它并没有回答所问的问题。 - Corey Goldberg
4
尽管“打包”是一个话题,但还有很多其他用例,例如用Python编写的部署脚本。 - hoefling

1
    import pip

try:
    import imaplib
    import email
    import pandas as pd
    # for hiding password
    from pathlib import Path
    from dotenv import load_dotenv
    import os
    import requests
    # 
    from collections import defaultdict
    from itertools import permutations,combinations
except Exception as e:
    print(e)
    e = str(e).split(' ')[-1].replace("'","")
    pip.main(['install', e])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接