Python项目的虚拟环境

Stella981
• 阅读 883

在开发 Python 项目时,首先要确定使用的 Python 版本,目前默认是 3.7(Python 2.7 已经在 2020 年停止支持了,但是需要维护的项目中肯定有不少基于 Python 2.x 版本的),其次会根据项目的需求来选择特定版本的第三方库(一般都会选择最新版本的,除非不同库之间有冲突)。但是使用 pip 安装第三方库时默认都会安装到 Python3 的 site-packages 目录中,一旦不同项目中的第三方库版本出现冲突时,就比较难处理了。所以我们需要对不同的项目开辟独立干净的空间进行开发部署,此时就需要 Python 的虚拟环境了。本文将介绍 virtualenv 和 pipenv 两种途径构建虚拟环境,但是 pipenv 的方式更值得推广

virtualenv

virtualenv 是一个创建隔绝的 Python 环境的工具。它会创建一个包含所有必要的可执行文件的文件夹,用来使用 Python 工程所需要的包。换句话说,我们可以用 virtualenv 给各个项目创建各自的 Python 环境,各个的环境之间安装的包相互独立,互不影响。通过激活 avtive 相应的 Python 环境来使用相应的 Python 环境。这里为了方便管理不同的 Python 环境,我们使用 virtualenvwrapper 来对 Python 虚拟环境进行管理。

安装和配置

virtualenv 和 virtualenvwrapper 的安装很简单,一条命令即可:

pip install virtualenv  # 安装virtualenv
pip install virtualenvwrapper # 安装virtualenvwrapper

virtualenv 是不需要配置的,它的使用直接是在项目文件夹里执行命令 virtualenv proEnv ,就会在当前项目目录下生成proEnv的目录,目录下会包含 bin,include,lib,local 这四个文件夹和一个 pip-selfcheck.json 文件。当该虚拟环境被激活后 source proEnv/bin/activate ,所有执行的 pip 安装程序都会安装在当前虚拟环境文件夹 proEnv 中。不过这样就导致下面的问题:

  1. 不方便管理--激活,消活 deactivate ,环境切换等
  2. 无法重用--存放在指定项目目录下

而 virtualenvwrapper 能完美解决这些问题。

virtualenvwrapper 的配置如下:

# 1.在~/.bashrc文件结尾添加下面(根据特定环境而定)
source /usr/local/bin/virtualenvwrapper.sh

# 2. 重新加载配置
source $HOME/.bashrc

常用命令

# 创建环境    
mkvirtualenv proEnv [-p python3.7]  # 在$HOME/.virtualenvs/目录下创建项目python环境

# 列举所有环境
lsvirtualenv

# 切换环境
workon proEnv

# 退出环境
deactivate

# 删除环境
revirtualenv proEnv

pipenv

pipenv 是 Pipfile 主要倡导者、requests 作者 Kenneth Reitz 写的一个命令行工具,主要包含了 Pipfile、pip、click、requests 和 virtualenv,能够有效管理 Python 多个环境,各种第三方包及模块。

pipenv 所解决的问题:

  • 不同项目依赖不同的第三方库、包版本问题( virtualenv 也可以解决)
  • 同一个项目不同环境使用不用的第三方库问题(比如 autopep8 , pylint , pep8 等只有开发环境需要)

pipenv的特性:

  • pipenv 集成了 pip,virtualenv 两者的功能,且完善了两者的一些缺陷。
  • 过去用 virtualenv 管理 requirements.txt 文件可能会有问题,Pipenv 使用 Pipfile 和 Pipfile.lock,后者存放包的依赖关系,查看依赖关系是十分方便。
  • 各个地方使用了哈希校验,无论安装还是卸载包都十分安全,且会自动公开安全漏洞。
  • 通过加载 .env 文件简化开发工作流程。
  • 支持 Python2 和 Python3,在各个平台的命令都是一样的。

TIPS:
《Flask Web开发实战》的作者在该书中使用了 Pipenv 作为包管理工具,但是在 2019 年 8 月又发表了博文不要用 Pipenv,其核心的槽点是 pipenv 在更新第三方依赖库时会更新所有依赖的包,其原因是对应的 packages 都是使用的星号*,未指定特定的包版本。所以在更新/同步等操作时会将所有未指定版本 (使用星号*)的第三方库给更新了。这里强烈建议生产环境的第三方库都指定版本

Pipfile.lock 文件更像是当前环境的一个快照,并不是指之前安装的第三方依赖库的版本就是确定的,除非你在 Pipfile 中限定好版本。

安装

pipenv 的安装很简单,一条命令即可:

# 安装pipenv包来管理依赖库
python3 -m pip install pipenv
# 设置环境变量,在项目目录创建虚拟环境.venv
export PIPENV_VENV_IN_PROJECT=1

常见的 Pipfile 配置如下所示:

[[source]]
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple"
verify_ssl = true

[dev-packages]
autopep8 = "*"
pylint = "*"
pep8 = "*"


[packages]
flask = "==1.1.2"

[requires]
python_version = "3.7"

常见命令

  • 创建虚拟环境

    开发环境安装 Pipfile 中第三方依赖

    pipenv intall -d

    生成环境安装 Pipfile 中第三方依赖

    pipenv install

    安装requirements.txt中的依赖库(项目迁移)

    pipenv install -r requirements.txt

    将pipenv的依赖库生成requirements.txt(项目迁移)

    pipenv run pip freeze > requirements.txt

  • 使用环境

    直接在虚拟环境中运行

    pipenv run python test.py

    激活虚拟环境,再运行脚本

    pipenv shell && python test.py && exit

  • 安装卸载第三方依赖

    安装第三方依赖库,并加到 Pipfile 的开发环境中

    pipenv install -d pylint

    安装指定版本的第三方依赖库,并加到 Pipfile 的生成环境中

    pipenv install Flask==1.1.2

    卸载第三方依赖库,并更新 Pipfile

    pipenv uninstall Flask

  • 查看依赖包

    查看当前环境依赖的包

    pipenv graph

虚拟环境的原理

pipenv 是基于 Pipfile,结合 pip 和 virtualenv来帮助开发者进行依赖管理,所以要想搞明白虚拟环境的原理其实只要把 virtualenv 的原理搞明白即可。 这里我们使用 pytyhon:3.7-stretch 镜像进行实验(不使用alpine镜像是因为它默认的 shell 是 ash,而不是 bash)。

现象分析

虚拟环境的特点有二:

  • Python版本固定。即使系统的Python升级了,虚拟环境中的仍然不受影响,保留开发状态。
  • 所有Python软件包,都只在这个环境生效。一旦退出,则回到用户/系统的默认环境中。

所以猜测 virtualenv 是通过改变 shell 的 PATH 来实现指定的 Python 版本,而对应的软件包是各自维护在各自的虚拟环境目录中的。

验证手段

  • echo $PATH Python 命令的查找路径
  • pip list 查看当前环境的依赖库
  • python -m site 打印当前 Python 环境和 site-packages 相关调试信息

验证

# 启动容器
docker run -it --rm python:3.7-stretch bash
# 安装virtualenv和virtualenvwrapper
pip install virtualenv virtualenvwrapper
# 在 $HOME/.bashrc 文件结尾添加 source /usr/local/bin/virtualenvwrapper.sh
echo "source /usr/local/bin/virtualenvwrapper.sh" >> $HOME/.bashrc
# 重新加载配置
source $HOME/.bashrc
# 创建虚拟环境proEnv
mkvirtualenv proEnv

容器当前的环境如下图所示: Python项目的虚拟环境 使用 workon proEnv 进入虚拟环境 proEnv 后,各参数如下图所示: Python项目的虚拟环境

对比 PATH 的变化,发现 virtualenv 将虚拟环境的 bin 目录置于 PATH 的最前方,所以当在终端执行 python 时,执行的是 /root/.virtualenvs/proEnv/bin/python, 而不是 /usr/local/bin/python。这就是为什么 virtualenv 没有影响本地的 Python 环境。

对比 python -m site 的结果,发现虚拟环境的 sys.path 中第三方依赖库的目录由 /usr/local/lib/python3.7/site-packages 换成了 /root/.virtualenvs/proEnv/lib/python3.7/site-packages。这就是为什么 pip list 看不见什么软件包的原因,也是环境隔离的最大秘密。

参考文献

  1. Pipenv中文文档
  2. python最佳实践指南
  3. Python开发还在用virtualenv?不如了解下pipenv
  4. 不要用 Pipenv

如果该文章对您产生了帮助,或者您对技术文章感兴趣,可以关注微信公众号: 技术茶话会, 能够第一时间收到相关的技术文章,谢谢!

Python项目的虚拟环境

本篇文章由一文多发平台ArtiPub自动发布

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
3年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这