返回顶部
首页 > 资讯 > 后端开发 > Python >《PyCon2018》系列一:Pipen
  • 144
分享到

《PyCon2018》系列一:Pipen

系列Pipen 2023-01-30 22:01:04 144人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

前言 俗话说,工欲善其事,必先利其器。我们写代码也是如此。在python开发过程中,如何管理python运行环境、package依赖关系是每个开发者都绕不过去的问题。在PyCon2018上,Kenneth Reitz介绍的Pipenv,就

前言

俗话说,工欲善其事,必先利其器。我们写代码也是如此。在python开发过程中,如何管理python运行环境、package依赖关系是每个开发者都绕不过去的问题。在PyCon2018上,Kenneth Reitz介绍的Pipenv,就是用来解决这类问题的大杀器。

为何需要Pipenv?

要想明白Kennenth Reitz为何开发Pipenv,还需要从Python的package管理工具的发展历史说起。

Python Packaging 历史

Distutils

早期的Python提供了一个名为distutils的内置模块。借助这个模块,开发者可以为自己的package创建setup.py文件,再全部打包上传到网上。当用户想安装这个package时,需要先从网上把文件下载下来(通常是tar包之类的),解压,然后执行python setup.py install,即可将其安装到Python的site-packages目录下。

PyPI

PyPI全称是Python Package Index,可以理解成一个集中式的索引,开发者们可以把他们的package及其metadata上传到这上面。有了PyPI之后,其他开发者就可以从这上面下载他们需要的package,然后执行python setup.py install进行安装。但即使这样,也还是存在着一些问题:

  • 整个过程需要人工介入,不方便自动化
  • package都是全局安装的,没法同时安装同一package的两个不同版本
  • 过程繁琐,用户体验差
Setuptools

Setuptools的出现,弥补了distutils存在的一些缺陷并提供了更加丰富的功能。Setuptools可以看作是对distutils的一系列扩展,包括支持egg安装文件、自动化安装工具(easy_install)以及对distutils的monkey-patch。有了easy_install,用户想安装某个package的时候,只需要执行easy_install <package>,工具会自动把package及其依赖(默认从官方的PyPI)下下来进行安装。与之前的package安装方式相比,easy_install有以下优点:

  • 更好的用户安装体验
  • 绝大多数package都来自PyPI
  • 更适合自动化

至于缺点嘛,最主要的就是:没有easy_uninstall。也就是说,你只能用easy_install安装package,却没有相应的工具用来卸载。

pip

到2008年,pip以easy_install替代者的身份出现了。虽然pip大部分也是建立在setuptools的各个部件之上,但它提供了比easy_install更加强大的功能,尤其是引入了Requirements Files的概念,使得用户可以非常方便地复制Python环境。我们可以在一个环境里执行pip freeze > requirements.txt,将当前环境的package信息全部导出,然后在新的环境里执行pip install -r requirements.txt,pip便会解析、下载并安装这些package。当我们不需要某个package时,还可以执行pip uninstall <package>将其卸载。直到现在,pip早已成为最受Python开发者青睐的package管理工具了。

virtualenv

pip解决了单个环境下的(大部分)package管理问题,但是我们通常会在一台机器上同时开发多个项目,项目A需要Python2.7以及flask0.9,项目B需要python3.6以及Flask1.0,而项目C需要Python3.6以及Flask1.0.2。如此一来,我们就面临着两个方面的问题:

  • 对于项目A和B或者项目A和C,如何区分它们所使用的不同版本的Python以及快速切换?
  • 对于项目B和C,由于它们都使用Python3.6,安装的第三方package都会放到Python3.6的site-packages目录下面,那么如何区分它们所需的不同版本的Flask?

对于第一个问题,可以把所需要的Python都装上,给它们指定不同的alias,在开发不同项目时使用不同的alias。这个方法可以工作,但是很繁琐,而且容易出错,如果开发者忘了使用alias或者使用了错误的alias,可能就会把package安装到错误版本的Python下面。
对于第二个问题,单靠pip就更难解决了,因为同个版本Python的所有第三方package都在site-packages下面,没法区分不同版本。

为了解决上述问题,我们需要一个新的工具,那就是virtualenv。virtualenv可以为每个项目创建一套隔离的Python环境,从而保证系统里不同的Python环境之间不会相互影响。在每个隔离的环境下面,再使用pip进行package管理。pip+virtualenv是目前比较主流的Python开发流程。

更进一步

前面提到,pip+virtualenv的工作方式成为了主流并延续至今。但是这种方式也有一些不足:

  • 新人(尤其是不懂Unix相关概念的新人)很难弄清virtualenv的抽象层是什么样的
  • virtualenv的工作流程比较繁琐,对人来说不够自然,尽管virtualenv-wrapper的出现一定程度上缓解了这个问题
  • pip的requirements.txt过于简单,没法表示具体的依赖关系
  • 需要使用两个工具(pip+virtualenv)才能完成工作,不够便捷

下面是在只安装了Flask的环境中执行pip freeze导出的requirements.txt。可以看到,里面包含了Flask本身及其依赖,每个package的版本都是确定的,但是没法看出它们之间的具体依赖关系是怎样的。试想,如果我们想使用一个开源项目,看到这样一个requirements.txt,我们可能会误以为这个项目直接依赖了这些packages,但实际上它只是直接依赖了Flask。

$ cat requirements.txt
click==6.7
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
Werkzeug==0.14.1

另一种requirements.txt的写法就是,我们只给定需要直接依赖的package名称,像下面这样。使用这种方式,我们一眼就能看出项目直接依赖了哪些package。但是这里有个问题,即Flask及其依赖的版本是不确定的。如果过段时间某个依赖发布了新版本,你去新环境部署的时候pip就会给你装上新的版本,可能会导致你的代码没法工作。

$ cat requirements.txt
Flask

以上就是Kenneth的演讲中举的例子,用来说明"what you want"和"what you need"之间的不匹配。

Pipfile & Pipfile.lock

为了解决"what you want"和"what you need"之间的不匹配问题,Pipfile这个新的标准被提了出来。

Pipfile被设计用来取代requirements.txt。其优点主要在于:

  • 采用TOML语法,相比requirements.txt表达能力更强
  • 默认支持两组依赖:[packages]和[dev-packages],可以将多个requirements.txt的内容合并到一个文件,方便管理
  • 可以通过Pipfile.lock对环境进行明确、详细地描述

Pipfile大致是这么个样子:

[[source]]  # source这部分指定从哪里获取package
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]  # default环境下需要的package
flask = "*"  # *表示任意版本,默认会安装最新版本

[dev-packages]  # dev环境下需要的package

[requires]
python_version = "3.6"  # 指定python版本

通过对Pipfile进行处理,可以生成JSON格式的Pipfile.lock,包含了所有依赖及其具体的版本号,还有每个release的hash。比如下面:

{
    "_meta": {
        "hash": {
            "sha256": "8ec50e78e90ad609e540d41d1ed90f3fb880ffbdf6049b0a6b2f1a00158a3288"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.6"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "Https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "click": {
            "hashes": [
                "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
                "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
            ],
            "version": "==6.7"
        },
        "flask": {
            "hashes": [
                "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
                "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913D44b43f05"
            ],
            "index": "pypi",
            "version": "==1.0.2"
        },
        "itsdangerous": {
            "hashes": [
                "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
            ],
            "version": "==0.24"
        },
        "jinja2": {
            "hashes": [
                "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
                "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
            ],
            "version": "==2.10"
        },
        "markupsafe": {
            "hashes": [
                "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
            ],
            "version": "==1.0"
        },
        "werkzeug": {
            "hashes": [
                "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
                "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
            ],
            "version": "==0.14.1"
        }
    },
    "develop": {}
}

大家可以理解成,Pipfile只描述了你想要的package是哪些,是抽象而宽泛的,比如上面Pipfile的例子描述了我们需要Flask这个package。而Pipfile.lock则是对你在实际运行环境里需要的package以及它们所有依赖的描述,是具体而明确的,比如上面Pipfile.lock的例子描述了Flask以及其依赖的具体信息,这样当我们想在新环境里运行我们的项目时,就可以按照这些信息来安装所有依赖的package,确保环境的一致性。实际上,很多语言的package管理工具都支持类似Pipfile.lock这样的Lockfile,比如node.js的yarn和npm,PHP的Composer,Rust的CarGo以及Ruby的Bundler。

Pipenv

Kenneth Reitz开发的Pipenv,将Pipfile,pip和virtualenv整合到了一起,让我们只使用这一个工具就可以非常方便、流畅地管理自己的Python环境。Pipenv的主要优点:

  • 可以让你无缝使用Pipfile和Pipfile.lock,保证每个依赖的信息都是明确的
  • 提供简洁的命令帮你操作virtualenv
  • 提供其他辅助工具,比如pipenv graph,可以显示项目完整的依赖关系

现在Pipenv已经是Python官方推荐的工作流(package管理+virtual env管理)工具了。

Pipenv用法简介

首先安装pipenv:

codehub@ubuntu:~/workspaces$ pip install pipenv

然后我们创建一个workspace并切换到该目录下(我这里是~/workspaces/pipenv_demo),创建一个新的环境:

codehub@ubuntu:~/workspaces$ mkdir pipenv_demo
codehub@ubuntu:~/workspaces$ cd pipenv_demo
codehub@ubuntu:~/workspaces/pipenv_demo$ pipenv install

如果要指定Python版本,可以使用--python参数:

codehub@ubuntu:~/workspaces/pipenv_demo$ pipenv --python /usr/local/bin/python3 install

创建完后,目录下就会生成Pipfile和Pipfile.lock两个文件:

codehub@ubuntu:~/workspaces/pipenv_demo$ ls
Pipfile  Pipfile.lock

下一步,我们安装Requests:

codehub@ubuntu:~/workspaces/pipenv_demo$ pipenv install requests

安装完毕之后,我们Pipfile就会变成下面这个样子:

codehub@ubuntu:~/workspaces/pipenv_demo$ cat Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
requests = "*"

[dev-packages]

[requires]
python_version = "3.6"

而Pipfile.lock则是这样:

codehub@ubuntu:~/workspaces/pipenv_demo$ cat Pipfile.lock
{
    "_meta": {
        "hash": {
            "sha256": "8739d581819011fea34feca8cc077062d6bdfee39c7b37a8ed48c5e0a8b14837"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.6"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "certifi": {
            "hashes": [
                "sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638",
                "sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a"
            ],
            "version": "==2018.8.24"
        },
        "chardet": {
            "hashes": [
                "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
                "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
            ],
            "version": "==3.0.4"
        },
        "idna": {
            "hashes": [
                "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
                "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
            ],
            "version": "==2.7"
        },
        "requests": {
            "hashes": [
                "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1",
                "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"
            ],
            "index": "pypi",
            "version": "==2.19.1"
        },
        "urllib3": {
            "hashes": [
                "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
                "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
            ],
            "markers": "python_version < '4' and python_version != '3.2.*' and python_version != '3.1.*' and python_version >= '2.6' and python_version != '3.3.*' and python_version != '3.0.*'",
            "version": "==1.23"
        }
    },
    "develop": {}
}

运行pipenv graph可以将环境中的完整依赖打印出来:

codehub@ubuntu:~/workspaces/pipenv_demo$ pipenv graph
requests==2.19.1
  - certifi [required: >=2017.4.17, installed: 2018.8.24]
  - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4]
  - idna [required: >=2.5,<2.8, installed: 2.7]
  - urllib3 [required: >=1.21.1,<1.24, installed: 1.23]

这个时候,如果我们直接运行Python交互模式,尝试import requests会报错,因为还没有激活virtual env:

codehub@ubuntu:~/workspaces/pipenv_demo$ python
Python 3.6.6 (default, Aug 25 2018, 10:34:56)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more infORMation.
>>> import requests
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'requests'

Pipenv提供了一个非常好用的命令:pipenv shell,用于激活virtual env:

codehub@ubuntu:~/workspaces/pipenv_demo$ pipenv shell
Launching subshell in virtual environmentâ¦
 . /home/codehub/.local/share/virtualenvs/pipenv_demo-B6h7SXri/bin/activate
codehub@ubuntu:~/workspaces/pipenv_demo$  . /home/codehub/.local/share/virtualenvs/pipenv_demo-B6h7SXri/bin/activate
(pipenv_demo-B6h7SXri) codehub@ubuntu:~/workspaces/pipenv_demo$

可以看到,当激活virtual env后,命令行提示符前面多了'(pipenv_demo-B6h7SXri)',这个就相当于我们virtual env的id,表示我们现在处于这个virtual env下。再次尝试在交互模式中import requests,成功:

(pipenv_demo-B6h7SXri) codehub@ubuntu:~/workspaces/pipenv_demo$ python
Python 3.6.6 (default, Aug 25 2018, 10:34:56)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> print(requests)
<module 'requests' from '/home/codehub/.local/share/virtualenvs/pipenv_demo-B6h7SXri/lib/python3.6/site-packages/requests/__init__.py'>

当不需要virtual env时,只需要运行exit即可:

(pipenv_demo-B6h7SXri) codehub@ubuntu:~/workspaces/pipenv_demo$ exit
codehub@ubuntu:~/workspaces/pipenv_demo$

通常我们需要把Pipfile和Pipfile.lock也加到版本管理中,以能保证同一个项目的不同开发者的Python环境保持一致。比如我们新加入了一个项目,就可以把repo clone下来,直接运行pipenv install,pipenv会自动找到已存在的Pipfile和Pipfile.lock,并根据里面的信息来安装依赖,这样我们就能准确无误地复制其他人的环境了。

总结

就像Kenneth Reitz演讲标题所写的那样,Pipenv是Python依赖管理的未来。作为一名合格的Python开发者,还是有必要学习下这个工具,提升自己的工作效率,也享受更好的工作体验。

参考

Pipenv - The Future of Python Dependency Management

--结束END--

本文标题: 《PyCon2018》系列一:Pipen

本文链接: https://lsjlt.com/news/179376.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 《PyCon2018》系列一:Pipen
    前言 俗话说,工欲善其事,必先利其器。我们写代码也是如此。在Python开发过程中,如何管理Python运行环境、package依赖关系是每个开发者都绕不过去的问题。在PyCon2018上,Kenneth Reitz介绍的Pipenv,就...
    99+
    2023-01-30
    系列 Pipen
  • python selenium系列(一)
    一  selenium是什么?引用百度百科的介绍selenium的一段话:“Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10...
    99+
    2023-01-31
    系列 python selenium
  • Prometheus系列(一)安装
    1 安装 Prometheus Server 官网:https://prometheus.io/ 下载:https://prometheus.io/download/ 手册:https://p...
    99+
    2023-10-25
    prometheus 服务器 grafana
  • Django 系列博客(一)
    前言 学习了 python 这么久,终于到了Django 框架。这可以说是 python 名气最大的web 框架了,那么从今天开始会开始从 Django框架的安装到使用一步步的学习,这系列博客不会像前端的那样水了(立个 flag),希望...
    99+
    2023-01-30
    系列 博客 Django
  • Redis系列(一)Redis入门
    NoSQL 开发中或多或少都会用到,也是面试必问知识点。最近这几天的面试每一场都问到了。但是感觉回答的并不好,还有很多需要梳理的知识点。这里通过几篇 Redis 笔记整个梳理一遍,后面再加上面试题。 Redis 系列: ...
    99+
    2020-02-02
    Redis系列(一)Redis入门
  • glance系列一:glance基础
    一 什么是glance二 为何要有glance三 glance的功能四 glance的两个版本五 镜像的数据存放六 镜像的访问权限七 镜像及任务的各种状态八 glance包含的组件九 glance与open...
    99+
    2024-04-02
  • mysql报错系列一(1251)
    1.报错问题 2.原因 因为MYSQL8.0之后更换了加密规则,用8.0之前的语句**alter user ‘root’@‘localhost’ identified by ‘xxxxx’;**来修...
    99+
    2023-09-17
    mysql 数据库
  • Python 系列(一)- 收藏集 -
    Python 多线程简易入门 - 后端 - 掘金一直懒得写Python相关的文章,恰好有天需要简单的给童鞋们讲点课,仓促之余就诞生了此文. 今天本来准备全面的聊聊有关高性能并发这个话题来着,但是周末马上要来了啊.所以我就取了其中的一点来介...
    99+
    2023-01-31
    收藏 系列 Python
  • Python之函数系列(一)
    每个编程语言中(诸如:Java、C++、C)等都有函数的,Python也不例外函数的主要作用有哪些呢?1、将程序的功能进行模块化,功能模块清晰2、减少重复代码的工作量3、便于阅读及维护、调试等一、函数的结束及返回值# -*- coding:...
    99+
    2023-01-31
    函数 系列 Python
  • Redis系列(一):小试牛刀
    随着互联网的高速发展,传统的关系数据库(如MySQL、Microsoft SQL Server等)已不能满足日益增长的业务需求,如商品秒杀、抢购等及时性非常强的功能,随着应用高并发的访问,会造成系统数据库崩溃,为了解决此种...
    99+
    2018-12-10
    Redis系列(一):小试牛刀
  • python入门系列之一:Centos6
    1)编译安装python2.7[root@mysql-master ~]# python -V Python 2.6.6 查看python的版本信息(之前的yum是通过yum安装的) [root@mysql-master src]# wge...
    99+
    2023-01-31
    入门 系列 python
  • OpenCV-Python系列·第十一集
    自定义卷积核,如3×3、5×5、7×7、9×9、11×11 Tip:卷积核需归一化。 # -*- coding: utf-8 -*- """ Created on Sat Aug 25 14:35:33 2018 @author: M...
    99+
    2023-01-31
    一集 系列 OpenCV
  • MySQL系列之一 MariaDB-server安装
    目录系列教程一、yum包管理器安装MariaDB-server二、官方二进制包方式安装MariaDB-server三、源码编译安装MariaDB-server系列教程 MySQL系列之开篇 MySQL关系型数据库基础...
    99+
    2022-05-30
    MySQL MariaDB-server安装 MySQL 安装 MariaDB-server安装
  • CBO的相关原理 系列一
    CBO的相关原理CBO在oracle7中被引入,基于数据对象的统计信息(包括数据集的行数,唯一值的个数等等)来计算执行计划的执行成本。随着版本的演化,CBO逐渐完善起来,在9i开始使用系统统计信息(syst...
    99+
    2024-04-02
  • 数据库MYSQL学习系列一
    数据库MYSQL学习系列一 一.MYSQL数据库基础1.1-认识MYSQL什么是数据库计算机处理和存储的一切信息都是数据计算机系统中一种用于存取数据的程序一种:计算机...
    99+
    2024-04-02
  • MYSQL学习系列--DML语句(一)
    引言: 数据操纵语言(Data Manipulation Language, DML)是SQL语言中,负责对数据库对象运行数据访问工作的指令集,以INSERT、UPDATE、DELETE三种指令为核...
    99+
    2024-04-02
  • Python学习系列 (第一章):Pyt
    一: Python 的简介:   python的创始人为吉多·范罗苏姆(Guido van Rossum)。1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承。二:Pyth...
    99+
    2023-01-31
    系列 Python Pyt
  • 【Java系列】详解多线程(一)
    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得,欢迎大家在评...
    99+
    2023-12-23
    java 开发语言 java-ee
  • 刷题系列 - 序列化和反序列化一个二叉树
    序列化和反序列化一个二叉树,是很开放的一题,就是给出一个二叉树,用序列化方法生成一个字符串;然后用反序列化方法把这个字符串生成原来二叉树。这个在编程时候各个类型一般都有序列化的,用于存储。这里面要用到python中list转化字符串方法 &...
    99+
    2023-06-02
  • MySQL进阶系列:一文详解explain
    explain有何用处呢: 为了知道优化SQL语句的执行,需要查看SQL语句的具体执行过程,以加快SQL语句的执行效率。 ​ 可以使用explain+SQL语句来模拟优化器执行SQL查询语句,从而知道mysql是如何处理sql...
    99+
    2019-12-13
    MySQL进阶系列:一文详解explain
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作