Zopfcode

かつてない好奇心をあなたに。

Pythonの環境管理ツール良し悪し

f:id:puhitaku:20200827170802j:plain

EDIT: 2018/06/19 pipenvについて追記

本記事は社内向けに書いた文章を修正したものである。

世の中にある代表的な「Python環境管理ツール」に virtualenv, pyenv, venv, pipenv の4つがある。これらをGoogleで検索すると使い方が書かれたページばかりが出てきて、それらの違いや使い分けを解説する記事は少ない。

本当は必要ではないのに「pyenvは便利」のような謳い文句で何となく使わせる記事や、古い情報を元に書いた「一見新しそうに見える記事」も多く見られる。

この記事では、中立・実用重視な視点から各ツールを解説し、筆者が考えうるベター(ベストは人それぞれ)な組み合わせについて書く。

なおAnacondaは初学者が使うにはおすすめできない。Anacondaについての筆者の解釈は末尾にあるためそちらも参照されたい。

本記事公開後いくつか近い話題の記事を教えていただいた。突っ込んだ話も多く参考になるので、末尾の参考欄から是非あわせて読んでいただきたい。

TL; DR

この文章で話すことをかんたんに言うと、

  • pyenvでPythonの複数バージョンを管理する
  • venvでパッケージ環境を切り分ける (Python 2ならvirtualenv)

以上の組み合わせが比較的シンプルながら柔軟でサポートが安定している。

非プログラマーの場合は、OSのパッケージマネージャーで最新のPythonをインストールした方が簡単でトラブルシュートしやすい。

用語

この記事では「バージョン」という言葉はPythonのバージョンを指し、同様に「バージョン管理」はPythonの複数バージョンをインストールしたり消したり切り替えたりすることを指す。

加えて「パッケージ環境」という言葉はパッケージが入ったディレクトリ一式、具体的には sys.path に列挙され探索される対象一式を指す。同様に、「パッケージ環境管理」という言葉はこのパッケージの組み合わせを切り替えたり作ったり消したりすることを指す。

ツールの用途比較と解説

今回比較するツールは以下の通り。

  • virtualenv
  • venv
  • pyenv
  • pipenv

以下については詳しく触れない。

  • Anaconda (本記事末尾を参照)
  • virtualenvwrapper (virtualenvの節を参照)
  • requirements.txtとかconstraints.txtとか「パッケージのバージョン管理」

virtualenv

用途: パッケージ環境管理

長所

  • 人気かつ歴史が長い
  • PyPAによってサポートされている
  • 作った環境を読んで動作を変えてくれるエディタもある(PyCharmなど)

短所

  • バージョン指定なしでも実行できてしまうため、どのバージョンのPythonインタプリタで実行されるかわかりにくい
  • 環境内にインタプリタ本体がごっそり入るので容量を食う

解説

深刻な欠点もなく、シンプルで挙動が理解しやすいツールだ。ただし virtualenv というコマンドを直接実行するとシステム標準のPythonと自分で入れたバージョンとがごっちゃになり事故が起きやすいので注意。

virtualenvwrapperを使えばどこからでもactivate/deactivateできるようになるが、virtualenvの動作を隠蔽しトラブルの種となりえるため初学者には向かない。

なおvirtualenvの機能はPython 3.3から「venv」という名前で標準ライブラリに取り込まれた。後述の利点に加え標準に則る観点からPython 3を使う場合はvenvを使うとよい。

venv

用途: パッケージ環境管理

長所

  • Python標準ライブラリ
  • virtualenvとほぼ同じなため使いやすい
  • インタプリタをコピーせずリンクを貼るだけなので環境あたりのサイズが小さい
  • バージョン指定をしない古い呼び方 pyvenv で呼ぶとwarningを出してくれるため事故が起きにくい

短所

  • 実行コマンドが冗長

解説

virtualenvが標準ライブラリに取り込まれ進化したもの。ほぼvirtualenv互換ながら標準ライブラリの手厚いサポートがあるため、venvがあるバージョンでvirtualenvをわざわざ使う理由はない。これからはvenvが業界標準となるだろう。 環境のサイズの小ささが特徴で、実際の bin ディレクトリの大きさ比較をしたのが以下の画像である。上がvenv、下がvirtualenv。

f:id:puhitaku:20170403234336p:plain

実際に利用する際は python3.6 -m venv my_env のようにvenvモジュールを直に実行する。打つのが面倒だが、Pythonのバージョンを明示的に指定するためPATH絡みの問題を回避できる。

Python 2ではvenvがないためvirtualenvを使い続けることになる。 とはいえこれからPython 2のコードを書き起こすケースはめったにないのでさほど問題にはならないだろう。 AWS Lambda で細々とPython 2を書いていたが、先日Python 3.6に対応したため本当にPython 2を書く理由が無くなった。素晴らしい!!!

pyenv

用途: バージョン管理 + パッケージ環境管理 (by virtualenv)

長所

  • shellで書かれていてPython自体に依存しない
  • pyenv install 3.6.1 のように打つだけで好きなバージョンがインストールでき、切り替えも容易
  • virtualenvへのバインディングを標準で搭載し、バージョンを切り替えるのと同じインターフェースでパッケージ環境も切り替えられる

短所

  • Python自体やPATHの挙動を理解しないうちに導入すると混乱の元となる
  • virtualenvの管理もできるが、pyenvのテリトリーに置くためPyCharm等が空気を読んでくれない

解説

virtualenv / venv はPythonのバージョンごとに入っているライブラリであり、Pythonのバージョンを切り替えるといったメタな管理は担当しないが、pyenvはここを担当できるツールとなる。

pyenvの最大の利点はPythonの複数バージョンを手軽に統一管理できる点だ。常に最新のPythonを入れるOSのパッケージ管理ソフトとは違い、パッチバージョン単位で好きに過去のバージョンをインストールでき、削除も簡単だ。この機能のためだけでもpyenvを導入する価値がある。

一方で、バージョン管理とパッケージ環境管理を統一した便利さと引き換えにPATHを操作する魔法が使われていて、とにかくトラブルになりやすい。shellをある程度理解しこれから本気でコードを書く立場の人なら良いが、Pythonは道具に過ぎないデータサイエンティストなどライトな層には向かない。

筆者は根っからのpyenvユーザーだが、最近はもっぱらPythonバージョンの切り替えのみ使っていて、パッケージ環境管理はvenvによるプロジェクト単位の管理に移行している。

virtualenvの管理でpyenvを使うのはおろかvirtualenv自体もvenvに取って代わろうとしているため、今後pyenv経由でパッケージ環境を管理するのは得策ではないだろう。

pipenv

用途: パッケージ環境管理とパッケージリスト管理の融合

長所

  • パッケージ環境の分離とパッケージリスト管理を融合して透過的に扱えるようにしたツール
  • requirements.txt による古典的なパッケージリスト管理を教訓に、リッチなパッケージリストフォーマット Pipfile を使用

短所

  • 裏で透過的にvirtualenvとpipを使っていて、ツールとしての直交性が低い
  • エッセンシャルにvirtualenv (venv)やpipの動作を理解したいと考えるならベストな選択ではない
    • 1つのツールとしてはよくできているので、割り切ってここから入るのも悪くない、かもしれない
  • Pythonに慣れた人からすると嬉しさがわかるものの、経験の浅い人が触るには暗黙的なコンテキストと情報量が多い
  • そもそもpipはPipfileを読めないなど、誰もが移行を検討するほどの勢力には至っていない

解説

pipとvirtualenvを融合させたモダンなツールであり、これらの動作を理解した次のステップとして有用なツールだ。「便利」の域を通り越して「必要」まで達しきれてない印象があるものの、単一のファイル名で使いみちがいろいろある requirements.txt よりかマシだと考える向きもあるだろう。ともかくパッケージ環境を切り分けるという点ではオーバースペックである。

Appendix: PipenvとPipfile

Pipenvは単一のツールとして語られることが多いが、この中で使われる Pipfile は、pipの管理団体であるPyPAによって提唱されている次世代の(requirements.txtconstraints.txt を置き換えうる)パッケージリストフォーマットであり、Pipenvはこれを扱える実装の1つである。もっとも、ごく初期にDonald Stufft氏がPipfileを立ち上げてからは pipenv の開発者である Kenneth Reitz氏 が Pipenv を作りながら策定を推し進めていたようだが…。

まとめ

ここまでの話をまとめると以下のようになる。

プログラマーの場合

Pythonが複数バージョンにまたがる際はpyenv (python-build)でインストールし、 pyenv global 2.7.10 3.5.2 3.6.1 のように使いたいバージョンをすべて有効化しておく。これでシステム標準のPythonを隠すことも達成できる。

パッケージ環境を分けたい際は python3.5 -m venv newenv のようにvenvで環境を作りactivate/deactivateする。PyCharmはこれを読んで自動で環境を切り替えてくれる。

なお id:orisano から「python-build単体でいんじゃね?」との提案があった。筆者の場合、いろんなバージョンを入れたり消したりするのが楽なのと、各バージョンの bin へのPATH通しが楽なため (shims) pyenvをそのまま使っている。もともとpyenvヘビーユーザーだからなのもあるが、ここは好みも大きいので各自工夫するのがいいと思う。

それ以外の場合(データサイエンティスト等)

Pythonは常に2/3の最新が使えれば良いので、apt/yum/homebrew等で最新のPythonをインストールしておく。パッケージ環境を分けたい際はプログラマーと同じくvenvを使う。

参考: Anacondaについて

Anacondaは簡単に言うと「最初からNumpyやJupyter Notebookが入っていて、ビルド済みバイナリをインストールすることで利用者の環境構築が省け、ついでに複数バージョンのPythonを管理したり環境を切り替えることもできる一大ディストリビューション」である。

響きはとても便利なのだが、何かと弊社内でもトラブルの根源となっているので初学者には使わないでほしい

Anacondaはそれひとつでエコシステムを形成しきってしまうものであり、最初からPythonが入っておらずビルド環境の準備が面倒なWindowsでは特に実用的である。しかしながらUNIX-like OSではビルド環境が要らない利点よりもシステム標準のPythonを遮蔽するなどの欠点が目立ちやすく、おまけにWebにあるAnaconda導入記事に低品質なものが多いせいで初学者がトラブルに陥るケースが少なくないのだ。

例えば、必要もないのにpyenvをインストールさせられてトラブルに陥り、結果pyenvやAnacondaの評判を落としかねない情報が拡散されるといった問題が取り沙汰されたのは記憶に新しい。

Anaconda開発元のContinuum Analyticsが書いたドキュメントでは公式インストーラーでの導入方法が丁寧に説明されているのだが、日本語での検索では日本語で解説している非公式の記事が優先的にヒットするため低品質な導入手順にぶちあたりやすい。

Pythonに慣れていない人でも踏み入れやすい素晴らしいディストリビューションながら、このように周囲のユーザーが複雑な・あるいは間違った情報を共有しているケースが大変多いのがAnacondaであり、初手でここから始めるのは強く避けるべきである。

参考

ドキュメント

ノウハウ・提言