python装包的n种姿势——包都装不上你写个锤子代码?

有的pythoner看到这个题目可能要指着作者笑:装包还需要你教?pip install package一键搞定有木有?

但据不完全统计,即使在pip如此流行的今天,包安装问题依然困扰着大部分的python新手,本人也经常帮一些工作经验三四年的python开发同事解决包安装的问题-_-!。那么接下来我们看下不同场景下python装包的解决方法:

Easy模式

通常情况下,你只需要键入以下命令即可安装成功,package为需要安装的包名:

pip install package

但有时候因为网络问题,并无法安装成功,毕竟pip默认的官网源在国外,这时候我们可以使用国内的pip源,你会感受到飞一般的下载速度。我常用的是aliyun的pip源,当然国内还有很多其他源供你选择,在此就不一一列出了。

切换国内源分为临时性和永久性两种,如果只是该次使用,在命令行后添加相应参数即可:

# 指定包名安装
pip install package -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
# 依据requirements.txt安装
pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

如果是想永久切换,可通过修改pip配置文件来达到此目的:

linux下修改~/.pip/pip.conf,如果没有该文件则创建;

windows下修改%HOMEPATH%\pip\pip.ini,如果没有则创建;

[global]
trusted-host=mirrors.aliyun.com
index-url=http://mirrors.aliyun.com/pypi/simple/

至此,我们已经能解决60%的装包问题了

Medium模式

如果你安装过某些用c语言编写的python包,会发现上一步的做法并不能安装成功,命令窗口弹出诸如下面的报错。如果你连这个错误都没遇到过,那说明你做的python项目真不多

fatal error: Python.h: No such file or directory

那装不上到底是为什么呢??

根据本文主题,我将python三方包粗略分为两类:

  1. 纯python编写的软件包
  2. c/c++语言编写的软件包

针对第二类情况,你需要确保系统上有对应的c/c++编译器及python开发者工具才能装包成功。

linux各个发行版,要先确保gcc、g++已经安装,然后再安装python开发者工具,以redhat/centos为例:

yum install gcc gcc-c++
yum install python-devel
# 或安装对应python版本的开发者工具
yum install python3-devel
yum install python36-devel

Debian/Ubuntu dev工具名字稍有不同,但思路一样

apt-get install python-dev

windows则需要安装vc++ for python x.x(即python对应的版本号),或者使用MinGw进行编译,参考阅读

Microsoft Visual C++ Compiler for Python 3.4​stackoverflow.compython装包的n种姿势——包都装不上你写个锤子代码?_第1张图片

如果你实在觉得麻烦,还有一个网站专门提供windows下的各种python包,可在不具备编译环境的情况下,选择合适自己的python环境进行安装,使用方法非常简单,pip install xxx.whl即可。网址如下,不谢

https://www.lfd.uci.edu/~gohlke/pythonlibs/​www.lfd.uci.edu

 

这个站点虽然不是万能的,但应付大部分在windows下开发的pythoner已经绰绰有余了。不过据本人亲身体会,一些的特定版本的包这个站点还真没有,所以我常用的开发模式其实是windows下跑ide,代码则共享至linux下运行,因为大家实际部署生产环境也是在linux,总之怎么舒服怎么来。

另外,有些包是需要相应的工具依赖的,例如pynmap,要求系统先安装了nmap,用的人一定要心里有数,不然可能将大量时间浪费在环境配置上。

Hard模式

需求一:

想象在某个极其恶劣的环境,老板给你提出了一个很不人道的需求:

小王,申请的服务器下来了,去把代码部署下吧

于是在某个风雨交加的晚上,你开始连接至生产服务器,手动部署代码,想着10分钟后就可以下楼撸串了,心里还有点小激动呢。然而登上服务器才发现:

  1. 生产服务器无法访问外网
  2. 公司搭建的内网pip源压根就不能用或者太久没更新压根就没你要的包

这时候真是叫天天不应,叫地地不灵。这种情况多见于国内的中、大型企业,有严格的网段划分和权限控制,但某些方面又做的不够好,比如源的管理问题。但活还是要干的,怎么办?

方法一:先将各个所需的三方包下载至本地,然后上传至服务器,挨个pip install。这里提醒一句,其实pip install package 或 pip install -r requirements.txt时,目标可以是包名,也可以是包的安装目录,所以聪明的pythoner,怎么提高效率你懂的:)

方法二:直接将三方包打包至项目代码中,简单粗暴,缺点是增加了项目代码体积

需求二:

在某个风和日丽的早晨,领导说:

小王啊,我们有个脚本需要部署到其他运维的服务器当agent用。

然后你经过调查发现脚本里面要用到一个三方包,但对方的服务器可能装过也可能没装过,于是你在脚本运行初始阶段设置了一个逻辑:

python装包的n种姿势——包都装不上你写个锤子代码?_第2张图片 

请仔细阅读以上代码 

然后你傻乎乎的调用了python的系统命令来执行包的安装操作,诸如os.system/os.popen/subprocess.Popen,发现并没有什么卵用,包确实执行安装了,但是代码初次运行的环境还是检测不到该包的存在,wtf?

经过一番分析发现,安装发生在脚本启动之后,上述安装方法并不会将新安装的包同步至当前的运行过程中,因为python脚本是在启动之初就将import的包导入当前内存中的,也就是说我们新安装的并没有被热更新过来,归根结底是因为动态装包的姿势不对,下面给出动态装包的代码示例,重点在于install函数部分,当年我可是在这个坑了待了好久才出来,说多了都是泪!_!:

import pip


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


# Example
if __name__ == '__main__':
    try:
        import xxx
        print('Yeah, the package is here, ready go')
        # todo run main code
    except ImportError:
        print('oh no, it seems like you must install this package then you can use it')
        install('xxx')
        # todo run main code

结语

至此,你已经基本领略了python装包99%以上的姿势,可以开开心心的coding了。如果你上面的都看完了,那么可以看下我一开始就想推荐的一篇文章,有点老,但通过了解python包管理工具的历史你对上述内容的理解会更深刻,同时又能体会到今天的世界是多么的美好。

Python 包管理工具解惑​blog.zengrong.net

 

当然,对于“包无法安装”这个问题,如果你还有其他更好的解决方案,或者对本文章有批评、指正或疑虑的地方,可在评论中指出,以便于我更新改正,谢谢捧场?

你可能感兴趣的:(python)