Pythonの仮想環境構築(2017年版) pyenvとpyenv-virtualenvとvirtualenvとvirtualenvwrapperとpyvenvとvenv 

## 追記 2017/01/29

突っ込み記事を書いていただきました。ありがとうございます。

+ [Pythonの仮想環境構築 2017.01版](http://ymotongpoo.hatenablog.com/entry/2017/01/29/002039)  

コメント欄で@shibukawaさんも述べられていますが、virtualenvとvenvはほぼ同じなので、実質はpyenv or virtualenv(venv)の２択だけど、virtualenvが既にデファクトスタンダードとして地位を確立しているとのこと。

記事内ではpyenv推しをしていますが、virtualenvを使うことにします。僕はライトPythonユーザなので周辺環境はできるだけデファクトに乗っかって楽をしたいので。

## はじめに

Pythonの環境構築について調べていると、タイトルに挙げたツール名を見かけることがあると思います。要は環境の隔離ツールなのですが、こういったツールは移り替わりが激しく、初級者にとっては何が何やらわかりません。僕自身そこまでヘビーにPythonを使いこんでいるわけではないので、それぞれの特徴や使い方をまとめてみました。

## その仮想環境本当に必要ですか？
Pythonは本格的な開発にも使えますが、日々のタスクを効率化するための治具ツールとしても大いに役立ちます。入門記事でもこれらの環境隔離ツールを使うことが当たり前のように書かれていたりしますが、不必要に敷居を挙げているだけで悪い習慣だと思います。自分用の便利ツールとして使っている間はこれらのツールは不要です。環境作りで疲弊するよりPythonによるプログラミングを楽しみましょう。

## テスト環境

+ OS Ubuntu16.04

```sh
    $ lsb_release -a
    ...
    Description:    Ubuntu 16.04.1 LTS
    ...

    % python3 --version
    Python 3.5.2

    % pip3 --version
    pip 9.0.1 from /usr/local/lib/python3.5/dist-packages (python 3.5)

    $ pip3 freeze | grep virtualenv
    virtualenv==15.1.0
    virtualenvwrapper==4.7.2

    $ pyenv --version
    pyenv 1.0.7-1-g99d1670
```

## 各ツールの関連性

6つもあって早速訳がわかりませんが、以下リストの通り、2つ組になっているので、実質は3種類と思っていいでしょう。

+ pyenv, pyenv-virtualenv
+ virtualenv, virtualenvwapper
+ pyvenv, venv

`pyenv-virtualenv`は`pyenv`のプラグイン。`virtualenvwapper`は`virtualenv`のラッパスクリプト？, `pyvenv`も`venv`のラッパといった扱いです。記事によっては、`pyenv-virtualenv`と`virtualenv`を混同しているものが見受けられるので注意しましょう。名前が紛らわしすぎますがこの二つは別物です。

## pyenvを試してみる
複数の異なるバージョンのPythonを利用したい時に使用します。複数のバージョンといってもPython2系3系という大きなくくりではなくて、
3.3と3.4、3.3.0と3.3.1といった細かいバージョン分けまで管理可能です。

バージョンごとのPythonの管理は、自分でバージョンごとに分けてインストールしてシンボリックリンクを適時張り替えればいいだけなので、そこまで大変な作業ではないのですが、特化したツールが一元管理してくれるのはやはり便利なものです。

pyenvを使用すると、新しいバージョンのPythonがリリースされたからちょっと試してみよう、といったことも手軽に行えます。

2017/01時点では残念ながらWindowsには対応していないようです。思いっきりシェルスクリプトメインで開発されているみたいなので、今後も対応は期待できそうにないですね。

```sh
    # インストール可能なバージョンがリスト表示されます。通常のPythonだけでなく
    # anaconda等のPythonディストリビューションや、jython, pypyといった別の
    # Python実装までリストされるのでビックリですね。
    $ pyenv install --list

    # バージョンを指定してインストール
    $ pyenv install 3.4.3
    $ pyenv install 3.6.0

    # フワッとしたバージョン指定をすると、該当するバージョンを
    # リストアップしてくれるので便利です。
    $ pyenv install 3.4

    python-build: definition not found: 3.4
    The following versions contain '3.4' in the name:
      3.3.4
      3.4.0
      3.4-dev

    # 新規インストールした後はこのコマンドを実行する必要があるそうです。
    # 自動でやってくれればいいじゃんとも思いますが。
    $ pyenv rehash

    # グローバルに使用するPythonバージョンの指定
    $ pyenv global 3.4.0
    $ pyenv version
    Python 3.4.0

    # ディレクトリローカルで使用するPythonバージョンの指定
    $ cd ~/project
    $ pyenv local 3.3.4
    $ pyenv version
    Python 3.3.4
    $ cd ~
    $ pyenv version
    Python 3.4.0

    # シェルローカルで使用するPythonバージョンの指定
    $ pyenv global 3.4.0
    $ pyenv version
    Python 3.4.0
    $ bash
    $ pyenv shell 3.3.4
    $ pyenv version
    Python 3.3.4
    $ exit
    $ pyenv version
    Python 3.4.0
```

**ワンポイント**  
どうやってディレクトリローカルのPythonという機能を実現しているのかというと、別に何かすごいことが行われているわけではなく基本アイデアは非常に単純です。
global指定されたPythonのバージョンは`~/.pyenv/version`というテキストファイルにそのまま文字列でPythonバージョンが保存されています。ディレクトリローカル指定をした場合は、ディレクトリ直下に`.python-version`というテキストファイルが作成され、そこにバージョン文字列が保存されます。
各バージョンのPythonは`~/.pyenv/versions`にバージョンごとに保存され、バージョン切替時は対応したPythonへのシンボリックリンクへの張替が行われるだけです。自分で同じようなことを実現させようとした時に真っ先に思いつきそうなアイデアですね。広く使われているツールも別に常に特別な技術が使われているわけではないので、完全なブラックボックスとして使うだけではもったいないよ、という余談です。

## pyenv-virtualenvを試してみる

`virtualenv`と`pyenv-virtualenv`は別のアプリーケーションです。記事によっては混同していることがあるので注意が必要です。
`pyenv-virtualenv`は`pyenv`のプラグインです。`pyenv`では複数のPythonバージョンをインストールできますが、各Pythonバージョンのモジュールを管理する`site-packages`というディレクトリは共通です。`pyenv-virtualenv`を使用すると同じPythonバージョンで別々の`site-packages`を管理することができます。
開発中のアプリーケーションで使用しているモジュールのバージョンを全て固定したり、必要最小限だけのモジュールをインストールしたりすることによって、開発環境と実行環境の違いを最小限にすることができます。

```sh
    # pyenv-virtualenvのインストール。
    $ git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv

    # .xxxrcに初期設定を追記する
    # 何故evalを使っているのか、オプションの`-`ってなんだ、と疑問に思ったのでスタックオーバーフローで質問してみました。
    #  http://ja.stackoverflow.com/questions/32043/xxxenv-の初期化時のeval-xxxenv-init-の意味
    vi ~/.bashrc
        eval "$(pyenv virtualenv-init -)"

    # pyenv virtualenv にPythonバージョンと仮想化環境を識別する任意の名称(tag)を指定します。
    $ pyenv virtualenv <pyversion> <tag>

    # するとそれに対応するsite-packagesディレクトリが生成されます
    Requirement already satisfied: setuptools in /home/vagrant/.pyenv/versions/<pyversion>/envs/<tag>/lib/python<X.Y>/site-packages
    Requirement already satisfied: pip in /home/vagrant/.pyenv/versions/<pyversion>/envs/<tag>/lib/python<X.Y>/site-packages

    # 作成した仮想環境はversionsから確認できます。
    $ pyenv versions
      system
      3.5.3/envs/virtual-3.5.3 # << この二つは多分同じ
      virtual-3.5.3            # << 

    # 作成したタグ名をactivateサブコマンドに指定すると、仮想環境が有効になります。
    $ pyenv activate <tag>

    # こんな感じでシェルのプロンプトの左にタグ名が表示されるはず
    (<tag>)$
  
    # 仮想環境を終了するにはdeactivateを実行します。
    $ pyenv deactivate

    # 通常のpyenvと同様にディレクトリローカルのvirtualenvも作成できます。
    # アプリケーション開発プロジェクトのルートディレクトリに対して、pyenv localを
    # 指定しておくとよいでしょう。
    $ pyenv local <tag>
```

### virtualenvとvirtualenvwapper

Pythonの歴史についてはあまり詳しくないですが、元々仮想環境構築ツールとしては、`virtualenv`が有名だったようで`pyenv`は後発のようです。`pyenv`を使ってから`virtualenv`を試してみると、確かに``pyenv`と比べて、こなれていない感を感じますね。  ~~`virtualenv`はPython本体のバージョン切替には使えませんし~~ (コメントで指摘を受けました。切替できるそうです)、site-packagesの隔離という面でみても、`pyenv-virtualenv`の方が使い勝手がいいように感じました。`pyenv, pyenv-virtualenv`の方が後発なので当然かもしれませんが、お役御免感がありますね。歴史が古い分エディタのプラグインサポート等の周辺環境については一日の長がありそうです。

新規で環境を作る分にはもう使うことはないかもしれませんが、一応一通りの機能はためしてみました。

#### virtualenv単体で使ってみる

```sh
    # virtualenvのインストール
    $ sudo pip3 install virtualenv

    # ディレクトリを指定して仮想環境を作成します。
    $ python3 -m virtualenv <dir>

    # するとこういったディレクトリが作成されます。ディレクトリ名はvirtualenvの
    # バージョンによってことなるかもしれません。
    # [確認環境] Ubuntu 16.04 virtualenv 15.1.0
    $ cd <dir>
    $ ls
    bin  include  lib  pip-selfcheck.json

    # 生成されたディレクトリのactivateスクリプトをsourceコマンドでロードすると
    # 仮想環境が有効になります。
    $ source bin/activate

    # 仮想環境が有効な間は仮想環境のルートディレクトリ名がプロンプト左に表示されます
    (<dir>)$

    # deactivateで仮想環境を終了します
    (<dir>)% deactivate
```

### virtualenvwapperを使ってみる

さてvirtualenv単体だと仮想環境の簡単な削除ができなかったり、virtualenv用のディレクトリが多数作成されたりと、もう一つ使い勝手が悪いですね。virtualenvwapperを導入すると、virtualenvを便利に使うためのユーティリティコマンドが使えるようになり、多少使い勝手がよくなります。
[virtualenvでpython環境を管理する](http://qiita.com/caad1229/items/325ca5c8ad198b0ebce7)を参考にインストールしてみました。

```sh
    # virtualenv / virtualenvwrapperのインストール
    $ sudo pip3 install virtualenv
    $ sudo pip3 install virtualenvwrapper

    # ~/.xxxrcに初期化コードを追記する
    $ vim ~/.bashrc
        source /usr/local/bin/virtualenvwrapper.sh
        export WORKON_HOME=~/.virtualenvs
```

再ログインして使ってみましょう。

```sh
    /usr/bin/python: No module named virtualenvwrapper
    virtualenvwrapper.sh: There was a problem running the initialization hooks.
  
    If Python could not import the module virtualenvwrapper.hook_loader,
    check that virtualenvwrapper has been installed for
    VIRTUALENVWRAPPER_PYTHON=/usr/bin/python and that PATH is
    set properly.
```

あらら、何やらエラーメッセージらしきものがでてきました。`pip3`でインストールしたので`python3モジュール`としてインストールされたわけですが、Ubuntu16.04の`/usr/bin/pythonはpython2.7`なので、`virtualenvwrapper`がインストールされてないよ。といっているようですね。`VIRTUALENVWRAPPER_PYTHON`にPython3のパスを指定すればよさそうです。なんと親切な作りでしょうか。見習いたいですね。設定を追加して再度ログインしてみましょう。

```sh
    $ vim ~/.bashrc
        export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
```

今度は別のメッセージができました。

```sh
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/initialize
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/premkvirtualenv
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/postmkvirtualenv
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/prermvirtualenv
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/postrmvirtualenv
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/predeactivate
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/postdeactivate
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/preactivate
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/postactivate
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/get_env_details
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/premkproject
    virtualenvwrapper.user_scripts creating /home/vagrant/.virtualenvs/postmkproject
```

中身を見てみると、ただのシェルスクリプトですね。イベント発生時にフックスクリプトを仕込めるようです。まあ今は無視しておきましょう。とりあえず普通に使ってみます。

```sh
    # virtualenvwrapperを実行すると、使用可能なコマンドがズラズラとでてきます。
    $ virtualenvwrapper

    Commands available:
  
      add2virtualenv: add directory to the import path
  
      allvirtualenv: run a command in all virtualenvs
      ...

    # mkvirtualenvで仮想環境を作成できます。--no-site-package未指定時は、
    # $VIRTUALENVWRAPPER_PYTHONのsite-packagesを引き継ぐようです。仮想環境を作る
    # 目的を考えると、通常は--no-site-packagesを指定した方がいいと思います。
    $ mkvirtualenv --no-site-package <tag>
  
    # 作成されるとコマンドプロンプトに一番左に環境名が追加される
    (<tag>)$

    # cdvirtualenvで仮想環境の本体？があるディレクトリに移動できます
    $ cdvirtualenv
    $ pwd
    /home/vagrant/.virtualenvs/<tag>

    # virtualenv単体の時は仮想環境ディレクトリ直下に配置されていたvirtualenvのディレクトリは
    # $WORKON_HOME配下に配置されるようです。ちょっとスッキリしましたね。
    $ ls
    bin  include  lib  pip-selfcheck.json

    # virtualenv単体ではできなかった仮想環境の削除も行えます。
    $ deactivate
    $ rmvirtualenv <tag>
```

### pyvenvとvenv

`venv`は`virtualenv`みたいな機能を標準でもサポートしようぜ！ということでPython3.3から追加された標準モジュールのようです。`venv`というコマンドがあるわけではんく、`python`からモジュールを指定して使います。

次にpyvenvについて調べていると、こういった記事がみつかりました。

[pyvenv は deprecated なので venv を使う話](https://jptomo.github.io/blog/2016/01310_not_use_pyvenv_but_venv.html)

また`pyenv`と`virtualenv`みたいなやつか・・・とゲンナリしていたのですが、もっと単純でした。結論からいうと、`pyvenv`は`venv`のシンタックスシュガーのようなもので、`pyenv`と`virtualenv`のように完全な別物というわけではありません。

```sh
    # venvの呼び出し方
    $ python3 -m venv <options>

    # pythonの標準ライブラリはUbuntu16.04では以下のディレクトリにインストールされています。
    $ cd  /usr/lib/python3.5
    $ find `pwd` -name "*venv*"
    /usr/lib/python3.5/venv

    # 2.7にはvenvはないようです。
    $ cd  /usr/lib/python2.7
    $ find `pwd` -name "*venv*"
```

pyvenvはUbuntu16.04では下記のパッケージをインストールすると使用できるようになります。

```sh
    $ sudo apt-get install -y python3-venv

    # dpkgで確認すると/usr/bin/pyenvが本体っぽいですね。
    % dpkg -L python3-venv
    /.
    /usr
    /usr/share
    /usr/share/doc
    /usr/share/man
    /usr/share/man/man1
    /usr/bin
    /usr/share/doc/python3-venv
    /usr/share/man/man1/pyvenv.1.gz
    /usr/bin/pyvenv
```

中身をみると、ホントにただ単に`venv`を呼び出してるだけですね。なんでわざわざこれを作成することになったのか謎です。
`pyvenv`がdeprecatedな理由は、参考リンクにもある通り、`python -m`で明示的にPythonのモジュールとして呼び出し方が、Pythonのバージョンが明確になってトラブラないじゃん！ということのようです。そんなん初めからわかるじゃん！といいたくなりますが・・・。以降は`pyvenv`を使用せずに`python -m venv`で説明をします。

```python
    # /usr/bin/pyvenv

    #! /usr/bin/python3.5
    if __name__ == '__main__':
        import sys
        rc = 1
        try:
            import venv
            venv.main()
            rc = 0
        except Exception as e:
            print('Error: %s' % e, file=sys.stderr)
        sys.exit(rc)
```

### venvを試してみる

```python
    # helpの表示
    $ python3 -m venv -h

    # 仮想環境の作成
    $ python3 -m venv <dir>

    # 何やらディレクトリが作成されています。virtualenvと同じような構成ですね。
    $ cd <dir>
    $ ls
    bin  include  lib  lib64  pyvenv.cfg  share

    # 使い方もvirtualenvと同じです。
    $ source bin/activate
    (dir)$ 
    $ deactivate
    $
```

標準だけあって随分シンプルですね。標準なのは嬉しいですが、3.3以上でないと使えなかったり機能不足だったりで、本格的な運用に使用するには物足りないように感じました。

--------------------------------------------------

### 総括

2017/01時点では`pyenv`と`pyenv-virtualenv`の組み合わせが最も使い勝手がよいのではないでしょうか。Windowsに未対応なのは残念ですが、本格的な開発をは仮想マシン上のLinuxを使うのがよさそうですね。
`virtualenv`はWindowsでも使えるので配布モジュールの動作確認をしたい時にクリーンな環境を構築する用途で使えそうです。`venv`でもいいですがPython2.7では使えないのが痛いですね。

治具ツールとしてPythonを使う分には、こちらのサイトの情報を参考にするのが最もシンプルだと思います。

+ [データサイエンティストを目指す人のpython環境構築 2016](http://qiita.com/y__sama/items/5b62d31cb7e6ed50f02c)

### 参考リンク

**pyenv, pyenv-virtualenv**  
+ [pyenvとvirtualenvで環境構築](http://qiita.com/Kodaira_/items/feadfef9add468e3a85b)  
    この記事はよくまとまっていますが、pyenv-virtualenvとvirtualenvを混同するような書かれ方をされていることに注意。  
+ [pyenv-virtualenvでディレクトリ単位のpython環境構築](http://qiita.com/niwak2/items/5490607be32202ce1314)

**virtualenv, virtualenvwapper**  
+ [Pythonでvirtualenvの使う方法](http://hikm.hatenablog.com/entry/2015/01/22/000448)
+ [pyenvとvirtualenvで環境構築](http://qiita.com/Kodaira_/items/feadfef9add468e3a85b)
+ [Pythonの仮想環境を構築できるvirtualenvを使ってみる](http://qiita.com/H-A-L/items/5d5a2ef73be8d140bdf3)
+ [Virtualenvwrapperの導入](http://qiita.com/_rdtr/items/5f3a9a9e2cb5a24f284e)
+ [virtualenvでpython環境を管理する](http://qiita.com/caad1229/items/325ca5c8ad198b0ebce7)

**pyvenv, venv**  
+ [pyvenv は deprecated なので venv を使う話](https://jptomo.github.io/blog/2016/01310_not_use_pyvenv_but_venv.html)
+ [Python3.3のvenvを試す](http://ymotongpoo.hatenablog.com/entry/2012/09/03/002604)