功能库

Python 的生命力大部分来自其众多的第三方功能库。这些功能库为 Python 提供了丰富而全面的功能。这些功能库可以使用 Python 自带的包管理工具 PIP 来进行管理。已经安装到 Python 的功能库可以直接导入到脚本中使用。

Python 并不提倡「重复制造轮子」的行为,如果有可以使用的第三方功能库,建议在项目中优先使用,自行编写功能库和「造轮子」是最后的选择。

PIP

PIP 是一个现代的通用的 Python 包管理工具,现在会随着 Python 的发布版本自动安装,提供了对 Python 包的查找、下载、安装和卸载等功能。PIP 在命令行中运行,常用的指令有以下这些。

  • pip install SomePackage,安装指定的包。
  • pip show SomePackage,查看相关包的信息。
  • pip list}`,查看已经安装的包。
  • pip list --outdated,列出目前存在更新的包。
  • pip install --upgrade SomePackage,更新指定的包。
  • pip search keyword,搜索包。
  • pip uninstall SomePackage,卸载指定的包。

在 Python2 和 Python3 共存的机器上,可以通过python3 -m pip <参数>的命令格式来执行 Python2 或者 Python3 中携带的 PIP。

如果 PIP 安装功能库缓慢,可以使用以下指令来设置 PIP 使用清华大学的安装源。

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

或者参考后文中的 pipenv 中提到的其他 Pypi 的源。

Conda

Conda 是一个随着 Anaconda 发行版发布的环境管理工具,与 PIP 一样提供了 Python 包的查找、下载、安装等功能,但是不同的是,Conda 的功能主要是偏向于环境管理功能,所以其可以直接在系统中创建和管理虚拟 Python 环境。不同的虚拟 Python 环境可以共存,并通过 Conda 进行激活和切换。Conda 常用的命令有以下这些。

  • conda create --name 环境名称 [库名称=版本,...],创建一个带有指定 Python 版本和库的环境。例如conda create --name py35 python=3.5}`将会创建一个使用 Python 3.5 版本解释器的虚拟环境。
  • conda env remove --name 环境名称,删除指定虚拟环境。
  • activate 环境名称,激活指定虚拟环境,macOS 和 Linux 使用source activate 环境名称
  • deactivate,关闭当前虚拟环境,macOS 和 Linux 使用source deactivate
  • conda install 库名称[=版本],向当前环境中安装指定库,并可以指定库版本。
  • conda remove 库名称,从当前环境中移除指定库,注意与删除环境的区别
  • conda update 库名称,升级当前环境中的指定库,可以用于升级 Conda 自身。
  • conda search 库名称,搜索指定库。
  • conda list,列出当前环境中安装的全部库。
  • conda env list,列出当前已经创建的环境。
  • conda env export > 文件名,将当前环境的配置导出到 YAML 文件中以方便共享。
  • conda env create -f 文件名,从导出的 YAML 文件中创建虚拟环境。

Conda 的命令和功能远不止以上这些,具体其他的命令和功能可以在使用时查询文档。

Warning

在日常使用中,需要注意 Conda 和 PIP 的功能区别,尤其是后文提到的使用virtualenvvenv库建立的虚拟环境与 Conda 建立的虚拟环境的区别。Conda 建立的虚拟环境是系统级的,用于支撑整个系统的,其级别层次要比 virtualenv 等库建立的虚拟环境层次要更加低一些。在开发中可以灵活搭配这两种虚拟环境来使用,而不是仅拘泥于使用其中哪一种。

在 macOS 和 Linux 中,Conda 可以直接在终端环境中使用。在 Windows 系统中需要在 Anaconda 安装的「Anaconda Prompt」程序中使用,当然如果你喜欢在命令行中使用也是可以的。

Anaconda 默认的软件包源中,可能包含的内容不足,并且访问速度较慢,这时我们可以使用以下命令来让 Conda 使用清华大学的源。

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes

# 以下是清华大学维护的第三方源

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/menpo/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/peterjc123/

加载到源文件

要使用功能库与模块,需要在另一个 Python 源文件中执行import语句,当解释器遇到 import 语句时,就会在当前的全部搜索路径中进行搜索并导入。解释器会优先搜索当前项目的路径,之后是所有库目录的列表。Python 的搜索路径保存在 sys 模块的 path 变量中,可以在交互式解释器中查看。

一个模块只会被导入一次,这可以防止模块被一遍又一遍的执行以及递归导入的出现。

import module

这是最普通的导入语句了。它会将目标模块内容导入到当前脚本中,但是如果需要访问其中的内容,需要使用\lstinline|module.function|的全名模式,因为其不会对当前的命名空间作出任何修改,只是加载了一个新的命名空间供使用而已。例如:

import sys
print(sys.path)

Warning

注意,这里所提到的所有 module,都是指点模块名称,即package.module的全名格式。

from module import ...

import module不同,这条导入语句可以将指定模块的一个指定部分导入到当前的命名空间中。这里用一个示例来说明。

假如有这样一个模块:

# fibo.py

def fib(n):
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
        print()

使用import module的格式来使用这个函数的方法如下:

import fibo

fibo.fib(1000)

但是如果使用from module import ...的格式来使用这个函数的方法则是:

from fibo import fib

fib(1000)

仔细对比函数的调用,就会理解from module import ...是如何工作的。

from module import *

这个引入操作更加容易理解,它将把指定模块中的全部内容都导入到当前的命名空间中。这个导入语句并不建议使用,因为这种导入非常容易造成命名空间中成员重名的情况。

前面提到了,模块可以使用包来组织,那么对于之前的示例使用from father_package import *会出现什么情况?如果在__init__.py中没有定义任何内容,这条引入语句是不会引入任何内容的。这是因为在包是依赖文件系统来组织模块的,Python 不能保证每个平台(尤其是 Windows)上模块的名称都是唯一的,比如 Windows 是不区分大小写的,DOS 对大于 8 个字符的文件名称有特殊处理,Linux 是区分大小写的。

这就需要在__init__.py中使用__all__来定义一个精确的列表,用来指示哪些模块是可以被导入的。当然,如果不使用from package import *的方式引入库,也是不必要去定义__init__.py的内容的。