Python环境构建

越来越多的人使用Python进行机器学习方面的工作。本文大致整理了目前现阶段构建Python开发环境的方法以及牵涉到的工具。同时,也会大致介绍机器学习方面常用的软件包。

前言

越来越多的人使用Python进行机器学习方面的工作。

在开始工作之前,自然需要先构建环境,但很多这方面资料都不够详尽。这对刚入门的初学者不是很友好。

还有一些时候,由于资料的年代过于老远,以至于所使用的环境已经不再适用。这导致不少人要耗费比较多的时间在环境构建上。

针对于此,本文大致整理了目前现阶段构建Python开发环境的方法以及牵涉到的工具。同时,也会大致介绍机器学习方面常用的软件包。

本文写于2020年初,将以当前主流的操作系统和软件版本为基础。

操作系统版本

对于开发者而言,不推荐大家使用Windows系统。本文使用开发者最常使用的macOS和Ubuntu系统为基础构建环境。对于其他Linux发行版的用户来说,本文应当也是适用的。

本文使用的系统版本如下:

  • macOS Catalina(10.15)
  • Ubuntu 18.04.3 LTS

Python 环境

无论在macOS还是Ubuntu上,默认的 python 命令都是指的Python 2的版本。但这个版本将从 2020年开始逐渐退出历史舞台

因此本文下面的内容只会涉及Python 3的内容。

考虑到可能只有少部分人会这么做,因此本文不提及如何从源码安装Python。如果你真的想这么做,可以参考这篇文章: Installing Python 3.5.1 from source

Python版本

通常,Python 2的命令为 python ,而Python 3的命令为 python3 。大家可以通过下面这条命令查看Python 3的具体小版本号:

$ python3 --version

下文中,如果不加说明,所说的Python都是指Python 3。

macOS上安装

macOS Catalina上自带了Python 2,但是没有Python 3。

不过如果你在命令行中输入 python3 ,则会弹出下面这个对话框让你安装。

点击“Install”并同意协议之后,便会自动开始安装。

这种方法应该是最便捷的安装方式。但是除了这种方法,还有下面几种安装方法也很常用:

  • 和Xcode一起安装:如果你安装了Xcode,你会发现其中也包含了Python 3。其路径通常是这样:/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/。
  • 通过Python Installer安装。链接如下: Python Releases for Mac OS X
  • 通过 Homebrew 安装。

相较而言,通过CommandLineTools方式安装最简单;通过Xcode安装则要占用较多的存储空间;通过Installer可以自主选择版本号(包括小版本号);通过Homebrew安装则卸载更新比较方便。

如果你的系统上已经有了 python3 ,但是不确定安装在哪里,你可以通过下文“环境确认”中提到的方法确认安装路径。

Ubuntu上安装

Ubuntu 18.04.3 LTS上正好相反:默认没有安装Python 2,不过安装了Python 3。但是其版本号比较低:

$ python3 --version
Python 3.6.8

大家可以安装一个更新的版本。在Ubuntu上通常通过 apt 命令来管理软件包,可以通过下面这条命令安装3.7版本的Python。考虑到版本兼容性的问题,这个版本可能是现阶段最合适的。

$ sudo apt install python3.7

通过 apt list 命令可以查看所有安装的软件包

在安装完成之后,系统中将有两个版本的Python(3.6和3.7)共存。但是系统默认并不会使用新安装的版本。不过我们可以改变默认的版本。

我们可以使用 update-alternatives 命令将新版本的可执行文件设置较高的优先级即可。该命令格式如下:

$ update-alternatives --install    

于是我们执行

$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 2

再次查看版本时,会发现 python3 已经指向新的版本:

$ python3 --version
Python 3.7.3

在这之后,如果还想要切换Python版本,可以通过下面这条命令选择默认版本:

$ sudo update-alternatives --config python3
There are 2 choices for the alternative python3 (providing /usr/bin/python3).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.7   2         auto mode
  1            /usr/bin/python3.6   1         manual mode
  2            /usr/bin/python3.7   2         manual mode

Press  to keep the current choice[*], or type selection number:

这个时候可以通过输入具体的数字来选择需要的版本。

环境确认

可以通过 which 命令查看 python3 命令的可执行文件路径。例如:

$ which python3                                                      
/usr/bin/python3

很多时候,这里返回的路径可能只是一个链接,因此还需要通过 ls -l 命令来确认:

$ ls -l /usr/bin/python3
lrwxrwxrwx 1 root root 25 11月  4 23:00 /usr/bin/python3 -> /etc/alternatives/python3

从这个输出可以看出,实际的 python3 可执行文件其实是 /etc/alternatives/python3

模块

绝大部分Python程序都不会是由一个文件构成,通常会包含了定义在多个文件中的内容。

你可以简单的认为,一个 .py 的Python文件就是一个模块。

严格的讲,Python中的模块有两种形式:

.py
.so

模块是程序的组成单元,它将代码和数据封装起来以便复用。同时,模块提供了自包含的命名空间从而避免程序出现变量名冲突。

以下面这个两行的代码为示例,这里导入一个名称为 platform 的模块。同时,也将这个模块命名为同名的变量。接下来我们就可以使用 platform 这个变量了。

import platform
print(platform.platform())

一个 import 语句中的模块名起到了两个作用:

  • 识别外部加载的文件
  • 赋值被载入模块的变量

通常,在程序中我们使用的模块有三个来源:

  • Python语言标准库中定义的模块。 这通常在安装Python的时候就一起包含了。可以到这里查看这些模块的说明: The Python Standard Library
  • 第三方开发者提供的模块。 这通常是一些开源软件,例如: numpypandas 等。
  • 通过源码形式使用的模块。 这通常是我们自己项目中开发的模块。

import 如何工作

与C/C++语言中的 #include 不一样。在Python中, import 并非只是把一个文件文本插入另一个文件。导入其实是运行时的操作。

程序第一次导入执行文件时,会执行三个步骤:

  • 搜索 :这一步是找到所引用模块的物理文件。具体见下面的“模块搜索路径”。
  • 编译(可选) ::如果需要,Python接下来会将模块编译成字节码。
  • 运行import 操作最后的步骤是执行模块的字节码。文件中所有的语句都会被执行。并且,此时任何对名称的赋值运算,都会产生所得到的模块对象的属性。

模块搜索路径

当我们使用标准库以外的模块时,我们很可能要关心 import 是如何搜索文件的。如果不然,我们很可能会遇到下面这个错误:

ModuleNotFoundError: No module named 'xxxx'

总的来说,Python会根据以下5个信息搜索模块:

路径 方式
程序主目录 自动
PYTHONPATH 环境变量中包含的目录 可配置
标准库目录 自动
任何 .pth 文件中的内容 可配置
第三方扩展应用的 site-packages 主目录 自动

这五个信息中包含的所有路径最终会组成 sys.path 列表。你可以通过下面的代码打印出这个列表:

import sys
print(sys.path)

Python始终会从左至右搜索这个列表以加载模块。因此优先级更高的路径将覆盖低优先级目录中的同名模块。

从上面的表格中我们也看到,Python提供了 PYTHONPATH 环境变量和 .pth 文件两种方式让我们配置搜索路径。

因此,通过 export PATHONPATH=xxx 的方式就可以将目录添加到搜索路径中。

.pth 文件的方式相对不那么常用。不过当存在 .pth 文件时,Python会把文件每行所罗列的目录从头至尾地添加到模块搜索路径列表中。

模块包

在Python世界里,“包”有两个含义:

  • 模块包(Module Package) :或者叫做导入包(Import Package),这是大家通常简称的“包”。这是一个Python模块,可以递归的包含其他包或者模块。
  • 分发包(Distribution Package) :这是版本化的存档文件,其中包含用于分发发行版的Python软件包,模块和其他资源文件。最终用户将从互联网下载并安装该该存档文件。

这其中,模块包对应了开发编码时的概念。分发包对应了构建项目环境时的概念。

这里我们先介绍模块包,下文会继续介绍分发包。

对于 import 来说,除了可以导入模块名之外,还可以指定目录路径。Python代码的目录被称为包,因此这样的导入就称为包导入。

模块包提供了组织多层次大型项目的功能。

如果选择使用包导入,就必须遵循一条约束。那就是:包导入语句的路径中每个目录内都必须有一个 __init__.py 文件(即便这个文件的内容可能是空的)。

例如,当我们使用 import dir1.dir2.mod 时。 dir1dir2 目录中都必须包含一个 __init__.py 文件。 __init__.py 文件承当了包初始化的职责。

当然, dir1 所属的父目录还要在 sys.path 列表列表中。

分发包

在开发Python程序时,单单标准库常常并不能完全满足我们的需求。我们还需要依赖其他第三方项目。这些项目以分发包的形式发布产物供我们使用。

这就要提一下PyPA和PyPI了。

PyPA (Python Packaging Authority)是一个工作组,负责维护Python打包中使用的一系列核心项目。

PyPA开发的软件用于打包,共享和安装Python软件,并与可下载的Python软件索引(例如PyPI)进行交互。

PyPA发布了 《Python Packaging User Guide》 作为有关如何使用当前工具打包,发布和安装Python项目的权威资源。

PyPI (Python Package Index)是Python社区的默认包索引。它对所有Python开发人员开放,使得他们可以使用它来获取和发布分发包。

常用机器学习包

在机器学习中,下面是一些大家常用的包。关于它们的更多信息可以访问官网获取。

  • jyputer
    • 官网: https://jupyter.org
    • 介绍:Jupyter Notebook(前身是IPython Notebook)是一个基于Web的交互式计算环境,用于创建Jupyter Notebook文档。借助这个工具,我们可以直接在浏览器里面编写和运行Python程序。
  • keras
    • 官网: https://keras.io
    • 介绍: Keras是一个用Python编写的开源神经网络库,能够在TensorFlow、Microsoft Cognitive Toolkit、Theano或PlaidML之上运行。Keras旨在快速实现深度神经网络,专注于用户友好、模块化和可扩展性。
  • matplotlib
    • 官网: https://matplotlib.org
    • 介绍:matplotlib是Python编程语言及其数值数学扩展包 NumPy的可视化操作界面。它利用通用的图形用户界面工具包,如Tkinter, wxPython, Qt或GTK+,向应用程序嵌入式绘图提供了应用程序接口。
  • numpy
    • 官网: https://numpy.org
    • 介绍:NumPy是Python语言的一个扩展程序库。支持高端大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
  • opencv
    • 官网: http://opencv.org
    • 介绍:OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。
  • pandas
    • 官网: https://pandas.pydata.org
    • 介绍:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
  • Pillow
  • protobuf
    • 官网: https://developers.google.com/protocol-buffers/
    • 介绍:Google开源的工具。一种数据交换的格式,它独立于语言,独立于平台。Google 提供了多种语言的实现:Java、C#、C++、Go 和 Python,每一种实现都包含了相应语言的编译器以及库文件。由于它是一种二进制的格式,比使用XML进行数据交换快许多。
  • scikit-image
  • scipy
    • 官网: https://www.scipy.org
    • 介绍:SciPy是一个开源的Python算法库和数学工具包。SciPy包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
  • tensorflow
    • 官网: https://www.tensorflow.org
    • 介绍:TensorFlow是一个开源软件库,最初由谷歌大脑团队开发,用于Google的研究和生产。它被用于各种感知和语言理解任务的机器学习。
  • turicreate

分发包管理

分发包管理主要牵涉到:分发包的打包和发布,分发包的安装,以及虚拟环境的管理。

分发包打包主要使用 setuptoolswheel 两个工具。

分发包使用称之为Wheel的格式发布。该格式由 PEP 427 – The Wheel Binary Package Format 1.0 定义。

打包和发布通常只有分发包的开发者才需要这方面知识,所以这里我们不讨论。接下来我们介绍分发包的安装和虚拟环境的管理。

pip

对于Python来说,使用 pip 来安装和卸载分发包。

Python 3对应的pip命令为 pip3

在macOS上,无论是通过上面提到的四种方法中的哪一种安装了Python(或者是通过源码安装),pip都会一并安装好。

查看pip版本时就能看到其所属的环境。例如,下面是通过CommandLineTools方式安装的Python。

$ pip3 --version
pip 19.0.3 from /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/site-packages/pip (python 3.7)

下面是通过Xcode方式安装了Python。

pip3 --version
pip 19.0.3 from /Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/site-packages/pip (python 3.7)

但是在Linux上就没这么方便了。你需要手动安装pip。

在Ubuntu系统上,通过下面这条命令安装pip3:

$ sudo apt install python3-pip

其他发行版的Linux安装pip的方法见这里: Installing pip/setuptools/wheel with Linux Package Managers

pip默认从 Python Package Index 上下载包。使用pip可以查询,安装和卸载包。下面是一些使用示例:

  • pip3 search 查询包信息:
$ pip3 search turicreate
turicreate (5.8)  - Turi Create simplifies the development of custom machine learning models.
  INSTALLED: 5.8 (latest)
  • pip3 install 安装某个包的最新版本:
$ pip3 install novas
Collecting novas
  Downloading novas-3.1.1.3.tar.gz (136kB)
Installing collected packages: novas
  Running setup.py install for novas
Successfully installed novas-3.1.1.3
  • 通过 == 安装某个包的特定版本:
$ pip3 install requests==2.6.0
Collecting requests==2.6.0
  Using cached requests-2.6.0-py2.py3-none-any.whl
Installing collected packages: requests
Successfully installed requests-2.6.0
  • pip3 install --upgrade 更新包
$ pip3 install --upgrade requests
Collecting requests
Installing collected packages: requests
  Found existing installation: requests 2.6.0
    Uninstalling requests-2.6.0:
      Successfully uninstalled requests-2.6.0
Successfully installed requests-2.7.0
  • pip3 show 查询包信息:
$ pip3 show scipy
Name: scipy
Version: 1.3.1
Summary: SciPy: Scientific Library for Python
Home-page: https://www.scipy.org
Author: None
Author-email: None
License: BSD
Location: /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages
Requires: numpy
Required-by: turicreate, scikit-learn, scikit-image, resampy, ImageHash
  • pip3 list 列出所有已经安装的包:
$ pip3 list 
Package               Version  
--------------------- ---------
absl-py               0.8.1    
astor                 0.8.0    
awscli                1.16.271 
boto3                 1.10.7   
botocore              1.13.7   
certifi               2019.9.11
chardet               3.0.4    
Click                 7.0      
colorama              0.4.1    
coremltools           3.0b3    
cycler                0.10.0
...

python -m pip

如果你的系统上同时有多个Python存在。那么直接运行 pip 命令可能并不是一个好的选择。因为这个时候很难确定使用的是哪一个环境中的。

在这种情况下,通过指定 python 可执行文件的全路径来运行pip会比较好。例如:

/Library/Frameworks/Python.framework/Versions/3.7/bin/python3 -m pip list

之所以可以这么做,是因为pip是Python一个模块。Python可执行文件提供了这样一个参数:

-m mod : run library module as a script (terminates option list)

关于这个参数的详细说明,请看这里: -m

虚拟环境

尽管不是必须的,但在一些时候,我们可能同时需要多个Python环境并存。

例如:某些项目需要专门的Python版本,或特定包的特定版本。又或者,某些包只在某个项目中使用,不希望它出现在全局的环境中。这个时候就可以通过虚拟环境来管理。

虚拟环境使得我们可以创建一个或多个隔离的环境,环境中包含了Python以及一系列的包,我们可以方便的在不同的环境之间切换,并且互不干扰。虚拟环境可以自由的创建和删除(这和我们电脑上使用的虚拟机是非常类似的)。

围绕这个方面的工具非常多,包括下面这些:

我们当然不会每个都介绍,关于它们的区分可以看下面的两个链接:

接下来仅仅介绍大家最为常用的两个。

venv

从Python 3.3开始,venv已经是Python标准的一部分。

但是即便如此,在Ubutnu上还是需要手动安装venv。并且安装时的版本号要与Python版本号一致。例如,安装Python时指定了3.7版本。则安装venv也要指定同样的版本:

sudo apt install python3.7-venv

venv模块提供了创建轻量级虚拟环境的功能。虚拟环境位于专门的目录中,可以与系统主目录相隔离。每个虚拟环境都有自己的Python二进制文件(与用于创建该环境的二进制文件的版本匹配),并且虚拟环境可以在其站点目录中拥有自己独立安装的Python软件包集。

创建虚拟环境的命令非常简单:

python3 -m venv 

这里的 是你可以任意指定的目录。如果该目录不存在,则会自动创建。

这条命令执行完成之后, 中会出现关于虚拟环境的一系列文件。你可以通过 tree 命令查看其目录结构:

$ tree venv_dir
venv_dir
├── bin
│   ├── activate
│   ├── activate.csh
│   ├── activate.fish
│   ├── easy_install
│   ├── easy_install-3.7
│   ├── pip
│   ├── pip3
│   ├── pip3.7
│   ├── python -> python3
│   └── python3 -> /Library/Frameworks/Python.framework/Versions/3.7/bin/python3
├── include
├── lib
│   └── python3.7
│       └── site-packages
│           ├── __pycache__
│           │   └── easy_install.cpython-37.pyc
│           ├── easy_install.py
│           ├── pip
│           │   ├── __init__.py
│           │   ├── __main__.py
...

Mac上默认没有 tree 命令。如果你安装了 Homebrew ,你可以通过它来安装: brew install tree

刚创建的虚拟环境是没有生效的,你还需要通过下面这条命令将其生效:

source /bin/activate

执行完成之后,命令提示符会包含虚拟环境名称的前缀。同时,你也可以通过 which 命令查看新的Python可执行文件路径:

(venv_dir) $ which python3
/Users/paul/Downloads/venv_dir/bin/python3

在这之后,你再通过 pip3 来安装包将安装在虚拟环境所在的目录中。

如果你想退出虚拟环境回到系统主环境,输入 deactivate 即可。

virtualenv

virtualenv是一个第三方包,所以通过pip安装即可:

pip3 install virtualenv

如果出现 Permission denied ,则需要带上 --user 参数,只为当前用户安装:

pip3 install --user virtualenv

venv和virtualenv有稍许不一样的地方,对比如下:

venv virtualenv
只支持Python 3.3+ 支持Python 2.7+
Python标准一部分 第三方分发包
使用链接,而不是拷贝python可执行文件 拷贝python可执行文件

使用virtualenv创建虚拟环境的命令如下:

virtualenv 

事实上,venv的实现很大程度上是基于virtualenv的,因此两者非常相似。virtualenv虚拟环境的生效和退出与venv是完全一样的。

如果你通过diff工具(例如: diffmerge )对比两者生成的文件夹,你会发现文件列表都是几乎一样的。

Conda

有不少的Python开发者会使用Conda。

这是一个开源的包管理系统,它支持Windows,macOS和Linux。它支持的语言远不只是Python,还有R, Ruby, Lua, Scala, Java, JavaScript, C/C++, FORTRAN。

Conda作为软件包管理器可以查找和安装软件包。如果需要一个使用不同版本的Python的软件包,则无需切换到其他环境管理器,因为conda也是环境管理器。仅需几个命令,就可以设置一个完全独立的环境来运行该不同版本的Python,同时继续在正常环境中运行通常的Python版本。

Conda有三个产品可供选择:

  • Anaconda :免费,适合新手。自带了超过150个科学计算包。占用空间较大。
  • Miniconda :免费,占用空间小,可以方便的自行安装软件包。
  • Anaconda Enterprise :收费的商业版本产品。

另外,安装包会有带界面的版本和命令行版本。使用Conda,你不用再自己安装Python,Anaconda和Miniconda自带了Python 2.7,Anaconda3和Miniconda3自带了Python 3.7。

以下以Miniconda为例,介绍如何使用。

对于Miniconda来说,提供了macOS和Ubuntu的 .sh 安装脚本。下载安装脚本之后赋予可执行权限,然后运行该脚本即可完成安装:

$ chmod a+x Miniconda3-latest-MacOSX-x86_64.sh
$ ./Miniconda3-latest-MacOSX-x86_64.sh

默认的安装目录是用户Home目录下,会新建一个miniconda3目录。在安装之后选择激活,然后重启命令行就可以使用了。可以通过下面的命令确认:

$ which python3
/home/paul/miniconda3/bin/python3

conda的激活方式其实就是在shell启动脚本中插入了一些conda的初始化脚本。例如,在Ubuntu上查看 ~/.bahrc 可以看到这部分内容:

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/home/paul/miniconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/home/paul/miniconda3/etc/profile.d/conda.sh" ]; then
        . "/home/paul/miniconda3/etc/profile.d/conda.sh"
    else
        export PATH="/home/paul/miniconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

激活Conda之后,你就有了 conda 命令。使用该命令可以轻松的管理软件包。当然,Conda也支持类似虚拟环境的功能。其帮助说明如下:

$ conda --help
usage: conda [-h] [-V] command ...

conda is a tool for managing and deploying applications, environments and packages.

Options:

positional arguments:
  command
    clean        Remove unused packages and caches.
    config       Modify configuration values in .condarc. This is modeled
                 after the git config command. Writes to the user .condarc
                 file (/home/paul/.condarc) by default.
    create       Create a new conda environment from a list of specified
                 packages.
    help         Displays a list of available conda commands and their help
                 strings.
    info         Display information about current conda install.
    init         Initialize conda for shell interaction. [Experimental]
    install      Installs a list of packages into a specified conda
                 environment.
    list         List linked packages in a conda environment.
    package      Low-level conda package utility. (EXPERIMENTAL)
    remove       Remove a list of packages from a specified conda environment.
    uninstall    Alias for conda remove.
    run          Run an executable in a conda environment. [Experimental]
    search       Search for packages and display associated information. The
                 input is a MatchSpec, a query language for conda packages.
                 See examples below.
    update       Updates conda packages to the latest compatible version.
    upgrade      Alias for conda update.

optional arguments:
  -h, --help     Show this help message and exit.
  -V, --version  Show the conda version number and exit.

conda要比pip更加强大,以下是两者的对比:

conda pip
管理格式 二进制 wheel或者源码
包类型 任何 仅Python
虚拟环境 是的,内置 否,需要 virtualenv或venv
依赖检查
包来源 Anaconda和云端 PyPI

参考资料与推荐读物