Python - 开发环境

Python 解释器

编程语言主要有两类,解释型编译型,来自百度百科的解释:

计算机不能直接理解任何除机器语言以外的语言,所以必须要把程序员所写的程序语言翻译成机器语言,计算机才能执行程序。将其他语言翻译成机器语言的工具,被称为编译器。

编译器翻译的方式有两种:一个是编译,一个是解释。两种方式之间的区别在于翻译时间点的不同。当编译器以解释方式运行的时候,也称之为解释器。

编译型语言写的程序执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如 exe 文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe 文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高。

解释则不同,解释性语言的程序不需要编译,省了道工序,解释性语言在运行程序的时候才翻译,比如解释性 basic 语言,专门有一个解释器能够直接执行 basic 程序,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就要翻译一次,效率比较低。解释是一句一句的翻译。

编译型与解释型,两者各有利弊。编译型由于直接运行目标机器代码,无中间步骤,已针对平台优化,通常速度和效率高;解释型的抽象于平台,跨平台可移植性好。

:Python 语言是被解释还是被编译的?

Python 的实现方式和 Java 类似,想兼顾两者优势,Python 语言的默认解释器(从官方下载的 Python)是 C 实现的 - CPython(直接叫 Python),CPython 把 Python 程序编译成bytecode(称为中间代码),然后bytecode可运行在 CPython 的虚拟机上。

Python bytecode

Python 除了 CPython,还有多种实现 - JythonIronPythonCythonNumba/Anaconda等,针对不同的虚拟机:

Python implementations

不同的解释器是为了方便和其它技术集成,例如默认的 CPython,可以方便地用 C 为 Python 写扩展Cython,增加代码执行速度,而JPython则可以让 Python 程序里直接调用 Java Class。

既然有 C、Java、C#的 Python 解释器,还要提到一个特殊的解释器PyPyPyPy比默认的 CPython 快不少,可以到 5 倍,参考http://speed.pypy.org/,因为引入了个高大上的技术just-in-time (JIT) compilation。bytecode 还是要要翻译成目标机器语言,而 JIT 能加速这个过程,“粗略”地讲:

  1. 找出那些需要多次执行的 bytecode;
  2. 把它们编译成机器代码;
  3. 将它们缓存起来;
  4. 再次碰到同样的 bytecode 时,直接调用已经缓存的机器代码;

偷拿个JVM上的 JIT 示意图:
JVM JIT

JITJVM上得到了极大应用,号称还快过编译型语言的程序如 C/C++。PyPy 采用同样的技术:

PyPy JIT

  1. PyPy 的解释器是用 RPython 编写的,RPython 类似 Python,相当于 Python 的子集,而且是类型
  2. RPython 被编译成了的各种目标机器代码,默认的编译器实现是针对 C 的,但和 CPython 编译器比较,加入了 JIT,除了 C,理论上同样也可以有针对其它平台如 JVM 的实现

还有各种 Python 的解释器,编译器,扩展等,不过 CPython(默认)是最完整的 Python 解释器,即是官方,也是使用的首选。

Python 版本及各种包

软件开发像搭积木,除了语言本身,更重要的是依赖于各种第三方提供的模块,库,包(各种语言使用的名称不太相同)。做开发的都知道版本和兼容是个大问题,Python 有两个主流版本 2.x _&_ 3.x(互相不兼容)。Python 3 在 2008 年就出现了,只是最近才成为首选,但是仍然有众多的包是针对 Python 2 的(这也是 Pyhon 3 这么长时间无法流行起来的原因)。想象一下,你机器上同时有两个项目 A 和 B,A 是用 Python 2 开发的,而 B 是用 Python 3 开发的,怎么办?还有第三个项目 C,虽然也是用 Python 2 开发的,但是 A 依赖于一个第三方的包,版本是 1.0,C 也同样依赖此包,但需要的版本是 2.0(好乱,有没有),开发人员直接就要面对这个现实而头疼的问题,是用 2 呢还是 3 呢,切换用可以吗,同一个包不同的版本如何放在同一台机器上,怎么管理,如何只升级 C 用的包而又不影响 A 呢?嘿嘿,问题不是新的,方法也是不止一种的。

最简洁的方式是只维护单一环境,这可以采用虚机(Virtual Machine)或者Docker 容器来解决,针对每个项目建个 Python 的虚机或容器。这种隔离方式很干净彻底,是公司或团队或者项目开发的正确方式,但对个人来讲,”有时”重了点 - 不至于 print “Hello World”也需要起个虚机或容器。

Python 是“民间”发明的编程语言,不像现在很多流行语言如 Java、C#,有商业公司主导和支持,一开始就有大规模商业运用的场景,很多大规模软件开发的问题一开始是没有考虑或者没有方案的,所以出现各种民间自发解决方案如 pyenv,pip,virtualenv,pipenv,等等,比较混乱。

上面聊完背景知识,下面动手。

pyenv

pyenv 借鉴了 rbenv,可以用来管理 Python 解释器及其版本。pyenv 不依赖于 Python,通过shims,截胡所有的 Python 命令:

Shim 是一个小程序,可以透明地截取调用并修改调用参数,自己处理该调用或者把调用导向相应位置。

pyenv 的截胡是通过 Path 环境变量:

$(pyenv root)/shims:/usr/local/bin:/usr/bin:/bin

安装 pyenv

$ curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash

若更新已有的 pyenv

$ pyenv update

Mac 可以通过brew安装:

$ brew update
$ brew install pyenv
$ brew install pyenv-virtualenv
$ brew install pyenv-virtualenvwrapper

安装后,pyenv 会修改.bashrc:

export PATH="/home/zhonglun/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

使用 pyenv

$ pyenv
pyenv 1.1.4
Usage: pyenv <command> [<args>]
Some useful pyenv commands are:
commands List all available pyenv commands
local Set or show the local application-specific Python version
global Set or show the global Python version
shell Set or show the shell-specific Python version
install Install a Python version using python-build
uninstall Uninstall a specific Python version
rehash Rehash pyenv shims (run this after installing executables)
version Show the current Python version and its origin
versions List all Python versions available to pyenv
which Display the full path to an executable
whence List all Python versions that contain the given executable
See `pyenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/pyenv/pyenv#readme

列出所有可供安装的版本:

$ pyenv install -l
Available versions:

安装某个版本:

$ pyenv install 2.7.14
$ pyenv install 3.6.2

列出已安装了的版本:

$ pyenv versions
Available versions:

卸载某个版本:

$ pyenv uninstall 2.7.14

安装完 Python 的各种版本后,pyenv 有四种指明 Python 版本的机制:

  • shell:通过环境变量 PYENV_VERSION 指定
  • local:由当前或者父目录下的.python-version 文件指定
  • global:pyenv root(默认下是~/.pyenv)下面的 version 文件指定
  • system:系统安装的 python,不在~/.pyenv 之下,Mac 或 Linux 系统都自带 Python

显示当前有效的 Python 版本:

$ pyenv version

指定当前 shell 使用的 Python 版本:

$ pyenv shell 3.6.2

Windows

由于 pyenv 是基于 Linux shell 的机制,Windows 就“悲剧”了(Windows10 除外,Windows 有 Ubuntu 子系统,但我还未用过),可以先安装 Python 2,再安装 Python 3,但记住安装时,两个都要选择Add Python to Path Variable,安装好以后设置环境变量 PY_PYTHON,值为 3。由于在不同的路径下都有 Python.exe,检测 Path 环境变量:

C:\Python36\Scripts\;C:\Python36\;C:\Python27\;C:\Python27\Scripts;

确认 Python 3 在前,这样默认的 Python 版本为 3。通过 py 来间接调用其它版本的 Python:

> python
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.prefix
'C:\\Python36'
>>> import site
>>> site.getsitepackages()
['C:\\Python36', 'C:\\Python36\\lib\\site-packages']
>>>
> py -h
Python Launcher for Windows Version 3.6.2150.1013
usage: py [ launcher-arguments ] [ python-arguments ] script [ script-arguments ]
Launcher arguments:
-2 : Launch the latest Python 2.x version
-3 : Launch the latest Python 3.x version
-X.Y : Launch the specified Python version
-X.Y-32: Launch the specified 32bit Python version
> py -2
Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:25:58) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.prefix
'C:\\Python27'
>>> import site
>>> site.getsitepackages()
['C:\\Python27', 'C:\\Python27\\lib\\site-packages']
>>>

当然木有 pyenv 来得优雅。

Windows 上的另一个选择是Anaconda

Anaconda = Python 解释器 + 环境管理器 + 包管理器 + 很多第三方的包(特别是针对大数据和数据分析)

Anaconda 把 Python 连同 n 多的第三方库/包都打包好了,一个安装程序就行,很方便。Anaconda 有自己的包管理器 conda 不是 pip, 具体见conda vs. pip vs. virtualenv以及这个教程Why you need Python environments and how to manage them with Conda。这个方法有利有弊,好处是一个环境通吃,所需要的东西都有了;坏处是体积较大,fork 一个 virutalenv 不方便。

Python 的包管理 pip 和环境管理 virtualenv,下面会介绍。

pip

pip 用来安装、升级和卸载 Python 包,Python 已经自带。

之前的版本则需要另行安装(Python 2 ≤ 2.7.8 & Python 3 ≤ 3.3),假设安装的都是最新版本,所以如何手动安装 pip 这里就略过了

> python --version
Python 3.6.3
> pip --version
pip 9.0.1 from c:\python36\lib\site-packages (python 3.6)
> pip -h
Usage:
pip <command> [options]
Commands:
install Install packages.
download Download packages.
uninstall Uninstall packages.
freeze Output installed packages in requirements format.
list List installed packages.
show Show information about installed packages.
check Verify installed packages have compatible dependencies.
search Search PyPI for packages.
wheel Build wheels from your requirements.
hash Compute hashes of package archives.
completion A helper command used for command completion.
help Show help for commands.

在 Mac 上,注意有些 Python 的包,既可以用 pip 安装,也可以用brew安装,个人还是倾向用 pip。

pip 是最广泛的包管理器但不是唯一,开发人员里有不同的声音,包管理或者依赖管理是 Python 比较弱的一个方面。

virtualenv

从上面的sys.prefixsite.getsitepackages可以看到了 Python 的解释器和包安装的目录的不同,为解决版本和第三方包的冲突,引入了虚拟环境的概念,包含该 Python 项目所需的依赖,为每一个项目单独创建一个虚拟环境,,而且同一个环境可以在开发,测试,生产环境复用。

  • 安装 virtualenv:$ pip install virtualenv
  • 创建一个虚拟环境:$ virtualenv /path/to/project
  • 如果有多个 Python 版本,可以指定,而不是系统默认的那个:$ virtualenv –python=/usr/bin/python2.7 /path/to/project
  • 如果不想带入任何系统已安装的包(无第三方包),可以这样:$ virtualenv –no-site-packages /path/to/project

/path/to/project 就是当前目录下创建一个新的目录名,源代码等项目文件也置于此目录下。

  • 使用/path/to/project 的 virtualenv 必须先激活,否则使用的还是默认/系统环境:$ source /path/to/project/bin/activate
  • 退出则执行:$ source /path/to/project/bin/deactivate

virtualenv 默认把 Python 的解释器、依赖的包和项目文件放在一起不是那么干净,virtualenvwrapper 把 Python 的依赖集中放置在~/.virtualenvs 下,把它从/path/to/project 的目录中解耦出来:

  • 安装:$ pip-install virtualenvwrapper Windows 上要使用 virtualenvwrapper-win:$ pip install virtualenvwrapper-win
  • 创建:$ mkvirtualenv /path/to/project
  • 激活:$ workon /path/to/project
  • 删除:$ rmvirtualenv /path/to/project
  • 列出所有:$ lsvirtualenv 或者 $ workon

pipenv

virtualenv 和 pip 吧唧一合体,就出来了个pipenv

  • 安装:$ pip install pipenv
  • 创建虚拟环境:$ cd /path/to/project && pipenv –python 3.6
  • 激活该虚拟环境:$ pipenv shell
  • 安装包:$ pipenv install request
  • 删除包:$ pipenv uninstall request
  • 产生依赖包列表:$pipenv lock -r > requirements.txt

如果是已有 pip 环境,可以$ pipenv install -e . 或者 $ pipenv install - r requirements.txt 从 pip 过渡到 pipenv。

pipenv 会自动建立 Pipfile 和 Pipfile.lock 文件,Pipfile 的一个例子如下:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[dev-packages]
isort = "==4.2.15"
"autopep8" = "==1.3.3"
pytest = "==3.2.3"
[packages]
django = "==1.11.6"
django-debug-toolbar = "==1.8"
django-extensions = "==1.9.1"
[requires]
python_version = "3.6"

$ pipenv –skip-lock install request==2.18.4 可以忽略依赖检测(例如当包的版本有冲突时),此时 Pipfile.lock 将不会产生或者更新。

pipenv run 还可以直接运行 Python 而无需像 virtualenv 那样先激活($ source ……),例如 $ pipenv run py.test

默认情况下,pipenv 和 virtualenvwrapper 一样,虚拟环境创建在项目目录之外,如果不想这样可以通过指定环境变量 _PIPENV_VENV_IN_PROJECT=TRUE_,这样虚拟环境就变为 /path/to/project/.venv。可以通过 $pipenv –venv 知道当前虚拟环境的具体存放目录。

Docker

“Hello, world” Project in real world,目标:

  • 能够支持夸平台开发 - Windows、Mac OS、Linux
  • 能够支持本地开发,同时各种云或传统服务器部署
  • 能够重用

结果:virtualbox + vagrant + docker

  1. 准备 VM
    i. 安装 Virtualbox
    ii. 安装 Vagrant & plugins (hostsupdater cachier vbguest
    iv. 安装 Git(Windows 参考 https://git-scm.com/download/gui/windows,Mac 上比较简单,命令行直接 brew)
    iii. git init 或者 git clone 项目
    iv. 启动 VM,Vagrantfile 参考(待续)
  2. 准备 Docker
    i. SSH 登录 VM,Windows 可用 Cygwin,Mac 直接 Terminal/Terminal2
    ii. 更新 repo
    ii. 安装或更新 Git
    iii. 安装或更新 Docker
    iv. build Docker image,dockerfile 参考(待续)
    v. 启动 Docker
  3. 开发(Pycharm为例)(待续)

总结

如下:

  • virtualenv 和 virtualenvwrapper 不包含在 Python 2 或 3 中,需要另行安装。
  • Python 2 和 3 都可以使用 virtualenv。
  • virtualenvwrapper 是 virtualenv 的加强版。
  • 另外,pyenv-virtualenvpyenv-virtualenvwrapper两个扩展让 pyenv 不必另外使用 virtualenv 和 virtualenvwrapper(也不必安装),例如:$ pyenv virtualenv 3.6.2 /path/to/project。上面的 pyenv-installer 会把 pyenv、pyenv-virtualenv、pyenv-virtualwrapper 一起安装。
  • venv 包含在 Python 3 里,和 virtualenv 的目标相同,可把 venv 看作新版 virtualenv,但属于不同的工具,实现方式也不同。
  • 如果不知道用 Python 2 或 3,把 Python 3 作为系统默认,除非你已经有大量 Python 2 的源代码或者库
  • 若 Python 3,推荐pipenv 另外 Python 3.6 之前有个自带工具 pyvenv,已经不支持。
  • 若 Python 2,建议使用pyenv + pyenv-virtualenvwrapper,Windows 则只能用 virtualenv + virtualenvwrapper,另一个选项是 Anaconda
  • 正式项目建议采用容器技术
0%