Help us understand the problem. What is going on with this article?

pyenvとpyenv-virtualenvの自分流使い方

はじめに

同僚に「Pythonの開発環境って pipenv 一択ですよね」と言われて「いや、自分は pyenv + pyenv-virtualenvで不自由していないんだよな」と思いながらも「こう使えば良いよ」と渡せるものが無かったので書くことにしました。

pyenv / virtualenv とは

pyenvおよびpyenv-virtualenvに馴染みのない方に向けて説明しておきます。

まず、pyenvは「一つのマシンに複数のバージョンのpythonをインストールしてそれを切り替えて使える仕組み」です。例えば「新しいプロジェクトでは最新の3.8.5を使うけど、メンテナンスモードに入っている古いプロジェクトでは 3.6.9を使わなければならない」という時に一々Pythonをインストールし直していたら面倒ですよね。そんな時にpyenvを使えば複数のバージョンのPythonをインストールできて、それを切り替えて使うことができます。

そして virtualenv は「あるバージョンのpython環境を複数持つ仕組み」です。これによって「pythonはシステム全体で依存ライブラリを1セットしか登録できない」という問題を解決しようとしています。これが、プロジェクトごとにnode_moduels/というディレクトリ作ってその配下に依存ライブラリをインストールするnode.jsなどと違う部分です。

例えばプロジェクトAはrequestsとpytorchに依存していて プロジェクトBはpandasとnumpyに依存しているとします。プロジェクトAもBも同じバージョンのpythonで動くとするとそこに双方の依存ライブラリをインストールしなければならなくなります。でもそうするとライブラリ同士の衝突が起きてしまったりするかも知れません。それを避けるためにプロジェクトA用のpython3.8.5とプロジェクトB用のpythion3.8.5を作る。それをしてくれるのがvirtualenvです。pyenv-virtualenv はそのvirtualenvをpyenvの中でイイ感じに使えるようにした仕組みです。

インストール

macOSの人はhomebrewを使うのが一番簡単と思います。

$ brew update
$ brew install pyenv
$ brew install pyenv-virtualenv
$ echo 'export PYENV_ROOT="${HOME}/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="${PYENV_ROOT}/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

それ以外のOSの方、あるいは最新のpyenvがどうしても使いたいという方は GitHubのリポから直接cloneしてくるというやり方もあります。

pyenvのインストール

$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.bash_profile
$ source ~/.bash_profile

そして pyenv-virtualenvのインストール

$ git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

zshとか他のシェルを使っている方は ~/.bash_profileの代わりにそれぞれの設定ファイルに読み替えてください。

pyenvにはインストーラーもあるのでそれを使うのも手です。基本は上でやっていることをまとめてやってくれるだけですがお手軽ではあります。

$ curl https://pyenv.run | bash

使い方の基本

Pythonのインストール

pyenvのインストールが無事にできたらまずはpythonをインストールしていきます。その前にまずは利用可能なpythonのバージョンを確認します。

$ pyenv install --list

無印のバージョン番号だけのものが cpythonです。それ以外に、anacondaとかjpythonとかpypyとか色々選べます。その中から自分がインストールしたいバージョンを選んで

$ pyenv install <python-version>

とすればそのバージョンのpythonがインストールされます。

利用するPythonを指定する

上記のインストール手順を繰り返せば複数のバージョンのPythonをインストールできます。今現在インストールされているPythonのバージョンを確認したければ

$ pyenv versions

とすればわかります。例えば 3.8.53.7.9がインストールされている場合には

system
3.7.9
3.8.5

という感じで表示されます。ここで systemというのはpyenvではなくてOS側で用意されている pythonになります。 

で、この中から利用するPythonを指定するわけですが、指定にはグローバル、ローカルの二種類があります。グローバルは自分がいるディレクトリに関わらず適用される設定、ローカルは特定のディレクトリ以下に適用される設定です。設定方法は以下のようになります。

グローバル設定

$ pyenv global <python-version>

ローカル設定

$ pyenv local <python-version>

そして、pythonを起動する際にローカル設定→グローバル設定の順で見に行きます。例えば、

$ pyenv global 3.8.5
$ cd /Users/johndoe/projectX
$ pyenv local 3.6.9

とした場合、/Users/johndoe/projectX以下では python 3.6.9 が、それ以外のディレクトリでは3.8.5が使われることになります。

いま、どのバージョンが使われるのかを確認した時には

$ pyenv version

を使います。例えば上の例だと

$ cd /Users/johndoe/projectX
$ pyenv version
3.6.9 (set by /Users/johndoe/projectX/.python-version)
$ cd ..
$ pyenv version
3.8.5 (set by /Users/johndoe/.pyenv/version)

となります。そして、"set by ... "と書かれているように、実はどのバージョンを使うかはファイルに書かれているだけです。中身を見るとわかりますがこれらは単なるテキストファイルでバージョン番号か書いてあるだけです。pyenvはそれをみて使うpythonのバージョンを特定しています。

pyenv-virtualenvを使う

次にpyenv-virtualenvの使い方です。まずは

$ pyenv virtualenv <python-version> <env-name>

特定のバージョンのPythonのコピーを作ります。例えば、

$ pyenv virtualenv 3.8.5 projectA

とするとprojectA用の3.8.5が作られます。ここで pyenv versionしてみると

system
3.7.9
3.8.5
3.8.5/envs/projectA
projectA

と表示されます。今作った(コピーした)環境が利用可能なPythonとして登録されているわけです。3.8.5/envs/projectAprojectAの2つ作らているように見えますが実体は一つです。

あとは通常のpyenvと同じで、

$ cd /Users/johndoe/projectA
$ pyenv local projectA

とすればprojectAを専用の3.8.5環境として使えます。要らなくなったら 

$ pyenv uninstall projectA

とすれば綺麗サッパリ消してくれます。この場合も 3.8.5そのものは残っているので他のプロジェクトで使いたければまた pyenv virtualenv 3.8.5 ... とすれば新たな環境を作れます。

自分流の使い方

新しくプロジェクトを始めるときはこんな感じで使っています。

$ mkdir projectZ
$ cd projectZ
$ pyenv virtualenv 3.8.5 projectZ
$ pyenv local projectZ
$ pip install .... (必要なライブラリ)
$ pip freeze -l > requirements.txt

こうしてプロジェクトごとに一つ環境を作っています。さらに例えば別のバージョンでの動作確認をしたい場合には

$ pyenv virtualenv 3.7.8 projecZ-3.7
$ pyenv local projectZ-3.7
$ pyenv install -r requirements.txt

とするだけで切り替えができます。

まとめ

これまで長年使ってきた pyenv + pyenv-virtualenv の解説をしてみました。

これは pyenvの課題というよりもpipの課題なのですが、「依存関係を扱う仕組みが弱い」です。requirements.txtは手動でアップデートしなければならないし、pip freezeで作った場合は自分がインストールしたものだけでなくそれが依存しているライブラリも合わせてリストされてしまう。ライブラリのバージョンアップデートをする時も個別に pip install -Uして変更をrequirements.txtに反映。ちょっとやってられないです。

つまり、「pyenv + pyenv-virtualenvで不自由していない」はあまり正確ではなく「多少不自由しているけど pyenv + pyenv-virtualenvは小回り効くのでなんとかなってた」ということですかね。

そういった問題を解決するために pipenv が出来たわけですが、個人的には poetry の方が筋が良さそうだなと思っていたりします。そしていくつかのプロジェクトで使ってみてなかなか良さそうなのですが、poetryを入れたところで結局はpyenvは捨てられないし、今のままで良いかなと思っておりました。

が、poetryは内部で venv(python標準の仮想環境作成ツール)を使っていてプロジェクトごとに環境を作ります。ということは pyenv-virtualenv + pip を poetryで置き換えできそうですね。もう少し積極的に使ってみて、これまで出来ていたことが素直にできるのかどうかを確認してみたいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした