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

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

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

JIT在JVM上得到了极大应用,号称还快过编译型语言的程序如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
  • 正式项目建议采用容器技术
显示 Gitment 评论
0%