はじめに
こんにちは。INAPのShosukeです。
Pythonのバージョン管理ツール、パッケージ管理ツールは他の言語と比較して数が多く、さらにそれぞれが一定のシェアを持っているというカオスな状態です。
そのため、環境構築をする際にはそれらから選択をしなければなりませんが、如何せん名前が似ていたりするので混乱します。
そこで、本ブログでよく使用されるツールを比較して頭を整理していきたいと思います。
環境構築には何が必要?
Pythonの環境構築には以下の要素が必要です。
インタープリター(バージョン管理)
インタープリターは、Pythonプログラムを実行するためのソフトウェアです。Pythonのコードを読み込み、実行します。Pythonをインストールすることで、ローカルマシンにインタープリターがセットアップされます。
1つのPC上に複数のバージョンのインタープリターをインストールするためにバージョン管理ツールが使用されます。
パッケージ管理
パッケージ管理は、Pythonの拡張機能やライブラリを効果的に管理する方法です。これによって、他の人が作成した便利なモジュールを利用できます。pipというツールを使用して、パッケージのインストールやアップグレードを行います。
プロジェクト毎に、パッケージ管理を行うためにパッケージ管理ツールが使用されます。
結論
ryeがオススメです。
ryeは単体でインタープリターとパッケージを管理することができるので環境構築が簡単です。
また、PipenvやPoetryと使用感が似ていてすぐに慣れることができるのでスイッチングコストも低いと思います。
ただし、バージョン番号が1.0.0未満なので、安定性が気になる方はビルドが高速なasdf + Poetryや、利用者の多いpyenv + Pipenvの組み合わせがオススメです!
環境構築ツール紹介
バージョン管理ツール
asdf
asdf(Another System Definition Facility)は、複数のプログラミング言語のバージョン管理を行うためのツールです。asdfを使用することで、異なる言語のバージョンを切り替えて管理し、プロジェクトごとに適切なバージョンを使用することができます。
また、その他のバージョン管理ツールと比較してもロードが高速です。asdfを利用する時は、後述のパッケージの依存解決が高速なPoetryとの組み合わせると快適に開発を進めることができます!
特徴
- プラグインエコシステム
- 言語ごとにプラグインを提供しています。各プラグインは、対応する言語のバージョン管理を担当し、言語のバージョンの追加や切り替えをサポートします。
ディレクトリ構造
~/.asdf/ ├── .tool-versions ├── plugins/ │ ├── python/ │ ├── ruby/ │ ├── nodejs/ │ └── … ├── shims/ │ ├── python -> ~/.asdf/installs/python/3.9.6/bin/python │ ├── ruby -> ~/.asdf/installs/ruby/2.7.3/bin/ruby │ ├── node -> ~/.asdf/installs/nodejs/14.17.0/bin/node │ └── … ├── installs/ │ ├── python/ │ │ ├── 3.9.6/ │ │ ├── 3.8.12/ │ │ └── … │ ├── ruby/ │ │ ├── 2.7.3/ │ │ ├── 3.0.1/ │ │ └── … │ ├── nodejs/ │ │ ├── 14.17.0/ │ │ ├── 16.3.0/ │ │ └── … │ └── … └── … |
- ~/.asdf/
- asdfのインストールディレクトリ
- .tool-versions
- 各プロジェクトのバージョンを指定するためのファイル。プロジェクトごとに使用する言語やそのバージョンを指定する。
- plugins/
- 各言語のプラグインが格納されるディレクトリ。各プラグインは言語ごとにディレクトリが作成され、それぞれのプラグインに関連するファイルや設定が含まれる。
- shims/
- バージョン管理された各言語の実行ファイルへのシンボリックリンクが作成されるディレクトリ。shimsディレクトリ内のシンボリックリンクは、実際のバージョンへのパスを解決するために使用される。
- installs/
- 各言語のバージョンがインストールされるディレクトリ。各言語ごとに個別のディレクトリが作成され、その中にバージョンごとの実行環境が存在する。
メリット
- pythonだけでなく、あらゆる言語のバージョン管理に対応している。そのため、新しい言語を使うときにわざわざpyenvのような言語毎のバージョン管理ツールを調べてインストールする必要がない。
- pythonのバージョンをプロジェクト毎に切り替えることができる
- anyenvよりもロードが高速
デメリット
- asdfをインストールするだけでなく、python用のプラグインをインストールする必要があるので少し手間。
環境構築例
# asdfのインストール
$ brew install asdf
実行結果省略
$ asdf --version
asdfのバージョンが表示される
# pythonのプラグインをインストール
$ asdf plugin add python
# 3.10.12をインストール
$ asdf install python 3.10.12
python-build 3.10.12 /Users/shosuke/.asdf/installs/python/3.10.12
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.10.12.tar.xz...
-> https://www.python.org/ftp/python/3.10.12/Python-3.10.12.tar.xz
Installing Python-3.10.12...
python-build: use tcl-tk from homebrew
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.10.12 to /Users/shosuke/.asdf/installs/python/3.10.12
# カレントディレクトリ配下でPython 3.10.12を使用するように設定
$ asdf local python 3.10.12
# Pythonのバージョンを確認
$ python -V
Python 3.10.12
anyenv
anyenvは、複数のプログラミング言語のバージョン管理ツール(〇〇env系のツール)を統一的に扱うことができるツールです。anyenvを使用すると、Pythonだけでなく他の言語のバージョンも管理できます。
下のコマンドで使用できるバージョン管理ツールを確認できます。
$ anyenv install –list |
ディレクトリ構造
~/.anyenv/ ├── envs/ │ ├── pyenv/ │ │ └── … (pyenvのインストールディレクトリ) │ ├── rbenv/ │ │ └── … (rbenvのインストールディレクトリ) │ └── … ├── shims/ │ ├── python -> ~/.anyenv/envs/pyenv/shims/python │ ├── ruby -> ~/.anyenv/envs/rbenv/shims/ruby │ └── … (他の言語の実行ファイルへのシンボリックリンク) └── … |
- ~/.anyenv/
- anyenvのインストールディレクトリ。デフォルトではユーザーのホームディレクトリに.anyenvという名前で作成される。
- envs/
- 各言語のバージョン管理ツールがインストールされるディレクトリ。それぞれの言語ごとに個別のディレクトリが作成され、その中に言語の実行環境が存在する。
- shims/
- バージョン管理された言語の実行ファイルへのシンボリックリンクが作成されるディレクトリ。shimsディレクトリ内のシンボリックリンクは、実際の言語バージョンへのパスを解決するために使用される。
メリット
- 複数のプログラミング言語のバージョンを統一的に管理できる
デメリット
- asdfと比較してロードが遅い
環境構築例
# anyenvをインストール
$ brew install anyenv# 実行結果省略
# anyenvの初期設定を行う
$ echo 'eval "$(anyenv init -)"' >> ~/.zshrc$ anyenv install --init$ exec $SHELL -l
# pyenvをインストール
$ anyenv install pyenv$ exec $SHELL -l
# Python 3.11.4をインストール
$ pyenv install 3.11.4
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.11.4.tar.xz...
-> https://www.python.org/ftp/python/3.11.4/Python-3.11.4.tar.xz
Installing Python-3.11.4...
python-build: use tcl-tk from homebrew
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.11.4 to /Users/shosuke/.anyenv/envs/pyenv/versions/3.11.4
# カレントディレクトリ配下でPython 3.11.4を使用するように設定
$ pyenv local 3.11.4
# Pythonのバージョンを確認
$ python -V
Python 3.11.4
pyenv
pyenvは、Pythonのバージョン管理ツールの1つです。pyenvを使用すると、システム上で複数のPythonのバージョンをインストールし、プロジェクトごとに異なるバージョンを選択することができます。
ディレクトリ構造
~/.pyenv/ ├── versions/ │ ├── 2.7.18/ │ ├── 3.6.12/ │ └── 3.9.6/ ├── shims/ │ ├── python -> ~/.pyenv/versions/3.9.6/bin/python │ └── …├── version └── … |
- ~/.pyenv/
- pyenvのインストールディレクトリ。デフォルトではユーザーのホームディレクトリに.pyenvという名前で作成される。
- versions/
- 各バージョンのPythonがインストールされるディレクトリ。バージョンごとに個別のディレクトリが作成され、その中にPythonの実行環境が存在する。
- shims/
- バージョン管理されたPythonの実行ファイルへのシンボリックリンクが作成されるディレクトリ。shimsディレクトリ内のシンボリックリンクは、実際のPythonバージョンへのパスを解決するために使用される。
- version
- システム全体で称するpythonのバージョン情報が記載されています。
メリット
- pythonのバージョンをプロジェクト毎に切り替えることができる
- 日本語の記事が多い
環境構築例
# pyenvをインストール
$ brew install pyenv# 実行結果省略
$ pyenv —-versionpyenvのバージョンが表示される
# Python 3.11.4をインストール
$ pyenv install 3.11.4
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.11.4.tar.xz...
-> https://www.python.org/ftp/python/3.11.4/Python-3.11.4.tar.xz
Installing Python-3.11.4...
python-build: use tcl-tk from homebrew
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.11.4 to /Users/shosuke/.pyenv/versions/3.11.4
# カレントディレクトリ配下でPython 3.11.4を使用するように設定
$ pyenv local 3.11.4
# Pythonのバージョンを確認
$ python -V
Python 3.11.4
パッケージ管理ツール
rye
ryeはflaskの作者であるArmin Ronacherが開発したPythonのバージョン・パッケージ管理ツールです。
Pipenv, Poetryと同様にプロジェクト毎に独立した仮想環境を作成することができます。
ディレクトリ構造
my-project/├── .git ├── .gitignore ├── .python-version ├── README.md ├── pyproject.toml └── src └── my_project └── __init__.py |
環境構築
$ brew install rye
# プロジェクト作成
$ rye init my-project
success: Initialized project in my-project
Run `rye sync` to get started
$ ls -al
total 32
drwxr-xr-x@ 8 aoshima staff 256 10 6 11:07 .
drwxr-xr-x@ 5 aoshima staff 160 10 6 11:07 ..
drwxr-xr-x@ 9 aoshima staff 288 10 6 11:07 .git
-rw-r--r--@ 1 aoshima staff 93 10 6 11:07 .gitignore
-rw-r--r--@ 1 aoshima staff 7 10 6 11:07 .python-version
-rw-r--r--@ 1 aoshima staff 42 10 6 11:07 README.md
-rw-r--r--@ 1 aoshima staff 414 10 6 11:07 pyproject.toml
drwxr-xr-x@ 3 aoshima staff 96 10 6 11:07 src
# 使用するPythonのバージョンを変更する
$ cat .python-version
3.11.4
$ rye pin 3.10
pinned 3.10.13 in my-project/.python-version
$ cat .python-version
3.10.13
# 仮想環境を作成する
$ rye sync
Downloading cpython@3.10.13
Checking checksum
success: Downloaded cpython@3.10.13
Initializing new virtualenv in my-project/.venv
Python version: cpython@3.10.13
Generating production lockfile: my-project/requirements.lock
Creating virtualenv for pip-tools
Generating dev lockfile: my-project/requirements-dev.lock
Installing dependencies
Looking in indexes: https://pypi.org/simple/
Obtaining file:///. (from -r /var/folders/xg/1sjmx7pd3yd2fb0gwgl1dny80000gp/T/tmpazi9mow5 (line 1))
Installing build dependencies ... done
Checking if build backend supports build_editable ... done
Getting requirements to build editable ... done
Preparing editable metadata (pyproject.toml) ... done
Building wheels for collected packages: my-project
Building editable for my-project (pyproject.toml) ... done
Created wheel for my-project: filename=my_project-0.1.0-py3-none-any.whl size=1070 sha256=7868e92fb26f6668723e90d7e0506fabcf3eb5197f51d3f1e0b0295ae210457f
Stored in directory: /private/var/folders/xg/1sjmx7pd3yd2fb0gwgl1dny80000gp/T/pip-ephem-wheel-cache-nq0qd7ku/wheels/78/12/b9/db4c72ae1aebdfd866f484b59eb7b39f206b7d7d1080ae28b1
Successfully built my-project
Installing collected packages: my-project
Successfully installed my-project-0.1.0
Done!
# 仮想環境作成後のディレクトリ構造
$ ls -la
total 48
drwxr-xr-x@ 11 aoshima staff 352 10 6 11:15 .
drwxr-xr-x@ 5 aoshima staff 160 10 6 11:07 ..
drwxr-xr-x@ 9 aoshima staff 288 10 6 11:07 .git
-rw-r--r--@ 1 aoshima staff 93 10 6 11:07 .gitignore
-rw-r--r--@ 1 aoshima staff 8 10 6 11:12 .python-version
drwxr-xr-x@ 7 aoshima staff 224 10 6 11:15 .venv
-rw-r--r--@ 1 aoshima staff 42 10 6 11:07 README.md
-rw-r--r--@ 1 aoshima staff 414 10 6 11:12 pyproject.toml
-rw-r--r--@ 1 aoshima staff 183 10 6 11:15 requirements-dev.lock
-rw-r--r--@ 1 aoshima staff 183 10 6 11:15 requirements.lock
drwxr-xr-x@ 3 aoshima staff 96 10 6 11:07 src
$ rye run python -V
Python 3.10.13
メリット
- バージョン管理・パッケージ管理がryeだけで行える
- デフォルトでプロジェクトディレクトリ内に「.venv」ディレクトリが作成される
- デフォルトでgit管理してくれる
Poetry
Pipenvと同様の機能を提供し、PEP 518で制定されたpyproject.tomlというフォーマットで管理します。
Pipenvとは異なり、1ユーザである@sdispaterが主導し開発されています。
Poetryは操作も簡単ですしPipenvと比較してビルドが早いので、低スペックPCでも簡単に作成することができます。
ディレクトリ構造
my-project ├── README.md ├── poetry.lock ├── poetry_demo │ └── __init__.py ├── pyproject.toml └── tests └── __init__.py |
次のコマンドを実行するとvenvディレクトリがプロジェクトディレクトリ内に作成されます。
その他のオプションはここを参照してください。
# すべてのプロジェクトに適応させる場合
poetry config virtualenvs.in-project true
# カレントプロジェクトだけに適応させる場合
poetry config --local virtualenvs.in-project true
メリット
- Poetryでは、Pipenvと同様に以下の機能を提供する
- パッケージの依存管理
- lockファイルの生成
- 仮想化機能
- 環境共有の容易さ
- Poetryで環境を構築するとpoetry.lockというファイルが作成される。このlockファイルは環境構築時の各パッケージのバージョンはハッシュ値で管理している。
- そのため、このlockファイルを共有できれば自分と全く同じpythonの実行環境を共有することができる。
- Pipenvと比較して依存解決、lockファイルの生成が早い
- Poetryの依存解決には「PubGrub」というアルゴリズムが採用されており、Pipenvの「Backtracking」アルゴリズムと比較して早い。
- lockファイルの生成時にハッシュ値計算をする回数がPipenvよりも少ないので生成が早い
- Pipenvでは全てハッシュ値計算をローカルで行っている。それに対して、PoetryではPyPIのJson APIが提供するライブラリのハッシュ値を流用するので計算が少なくなる分lockファイルの生成が早くなる。ただし、ハッシュ値を提供しないライブラリもあるので、そのときはローカルで計算する。
- 参考URL
環境構築例
# poetryプロジェクトを作成
$ poetry new poetry-demo
Created package poetry_demo in my-project
# 作成したプロジェクトの構成
$ tree my-project
my-project
├── README.md
├── poetry.lock
├── poetry_demo
│ └── __init__.py
├── pyproject.toml
└── tests
└── __init__.py
3 directories, 5 files
# poetry環境にrequestsライブラリを追加する
$ poetry add requests
Creating virtualenv my-project-NWT31goc-py3.10 in /Users/shosuke/Library/Caches/pypoetry/virtualenvs
Using version ^2.31.0 for requests
Updating dependencies
Resolving dependencies... (0.4s)
Package operations: 5 installs, 0 updates, 0 removals
• Installing certifi (2023.7.22)
• Installing charset-normalizer (3.2.0)
• Installing idna (3.4)
• Installing urllib3 (2.0.4)
• Installing requests (2.31.0)
Writing lock file
# ライブラリ追加後のpyproject.toml$ cd my-project
$ cat pyproject.toml
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = ""
authors = ["shosuke <メールアドレス>"]
readme = "README.md"
packages = [{include = "poetry_demo"}]
[tool.poetry.dependencies]
python = "^3.10"
requests = "^2.31.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
# pipenvで作成したmain.pyと同じものを作成する
$ vim main.py
$ ls
README.md main.py poetry.lock poetry_demo pyproject.toml tests
# main.pyを実行する
$ poetry run python main.py
Your IP is {自分のIPアドレス}
Pipenv
PipenvはPyPAが開発するパッケージ管理ツールです。Pipfileというファイルを使用します。pipenvを使用することで、プロジェクト毎に独立したPythonの仮想環境とパッケージ管理ができます。
ディレクトリ構造
my-project/ ├── Pipfile ├── Pipfile.lock ├── .venv/ ├── src/ │ └── main.py └── … |
venvと同じように「.venv」ディレクトリを作成し、そこで仮想環境上のPythonのインタープリターやライブラリを管理します。
「.venv」ディレクトリの作成場所は設定によって変えられます。今回は便宜上、projectディレクトリの配下に置いています。
次のコマンドを「.zshrc」等に追加するとprojectディレクトリの配下に「.venv」ディレクトリが作成されます。
その他の環境構築の方法はここなどを参照してください。
export PIPENV_VENV_IN_PROJECT=1
メリット
- Pipenvでは以下の機能を提供し、Pipfileファイルで全て管理できる。
- パッケージの依存管理
- lockファイルの生成
- 仮想化機能
- 環境共有の容易さ
- Pipenvで環境を構築するとPipfile.lockというファイルが作成される。このlockファイルは環境構築時の各パッケージのバージョンはハッシュ値で管理している。
- そのため、このlockファイルを共有できれば自分と全く同じpythonの実行環境を共有することができる。
環境構築例
# requestsライブラリを追加して仮想環境を構築する
$ pipenv install requests
Installing requests...
Resolving requests...
Adding requests to Pipfile's [packages] ...
✔ Installation Succeeded
Pipfile.lock not found, creating...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
✔ Success!
Locking [dev-packages] dependencies...
Updated Pipfile.lock (a416d48a2c30d4acf425cb96d7ac6672753db8e8f6c962a328848db5b9a290a1)!
Installing dependencies from Pipfile.lock (a290a1)...
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
# PipfilePipfile.lockが作成される
$ ls
Pipfile Pipfile.lock
# 作成されたPipfileの中身
$ cat Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
requests = "*"
[dev-packages]
[requires]
python_version = "3.10"
# 自分のIPアドレスを表示するファイルを作成する
$ vim main.py
$ cat main.py
import requests
response = requests.get('https://httpbin.org/ip')
print('Your IP is {0}'.format(response.json()['origin']))
# 実行する
$ pipenv run python main.py
Your IP is {自分のIPアドレス}