---
title: "pyenvでPythonのバージョンを切り替える手順｜shimの仕組みとビルド失敗の対処"
url: "https://www.issoh.co.jp/tech/details/17513/"
published: 2026-09-09
updated: 2026-09-09
categories: ["Python"]
publisher: "株式会社一創"
---

# pyenvでPythonのバージョンを切り替える手順｜shimの仕組みとビルド失敗の対処

pyenvは、1台のマシンに複数のPythonを共存させ、プロジェクトごとに使う版を切り替えるコマンドラインツールです。Python本体はソースからビルドして `~/.pyenv/versions/` の下に並び、`python` というコマンド自体をpyenvが横取りして、そのディレクトリで指定された版へ振り分けます。この記事では、shimがPATHの先頭に入って動く仕組み、ビルド依存を揃えてシェルへ初期化を書くまでの手順、`global` / `local` / `shell` の使い分け、BUILD FAILEDや `sqlite3` 欠落の切り分け、uvが出てきた2026年時点でpyenvを使い続ける条件までを、公式の記述を出典として整理しました。

## まとめ：pyenvを入れる手順とuvへ寄せるべき分岐点の先出し

pyenvがやることは1つです。`$(pyenv root)/shims` をPATHの先頭に差し込み、`python` や `pip` の呼び出しを受け取って、現在のディレクトリで指定された版の実体へ渡す。版の決まり方は `PYENV_VERSION`、カレントの `.python-version`、親を遡って見つかる `.python-version`、`$(pyenv root)/version` の順です。

導入は3工程です。第1にOS側のビルド依存パッケージを入れる。ソースからコンパイルするため、ここを飛ばすとビルドが落ちるか、通ったあとで `import sqlite3` が失敗します。第2に本体を取得する（`pyenv.run` のインストーラかgit clone、macOSなら `brew install pyenv`）。第3にシェル設定へ `PYENV_ROOT` とPATHと `pyenv init` の3行を書く。

判断はこうです。2026年に新規で立ち上げるなら、uvを選ぶほうが手数が少ない。uvはPythonを事前ビルド済みバイナリで落としてくるため、ビルド依存を揃える工程が消えます。pyenvが残るのは「既存システムがEOL寸前の版に固定されている」場面と「CPython以外の実装を並べたい」場面だけ。

## shimをPATHの先頭に挿してPythonを差し替える仕組みの把握

pyenvの挙動が読めなくなる原因は、ほぼPATHとshimに集まります。先に構造を掴むと調査が短く済みます。

### shimsディレクトリがpythonコマンドを横取りする経路

[pyenvの公式リポジトリ](https://github.com/pyenv/pyenv)のREADMEには、pyenvが `$(pyenv root)/shims` をPATHの先頭へ挿入してPythonコマンドを差し込むと書かれています。shimはPython本体ではなく、数十行のシェルスクリプトです。`python` を叩くとまずこれが動き、使うべき版を決めてから `~/.pyenv/versions/<version>/bin/python` を `exec` する。

pyenv自体はPythonで書かれていません。READMEには「Python自体に依存しない純粋なシェルスクリプト」という趣旨の記述があり、壊れた版のアンインストールがPythonに依存しない設計です。この方式はRubyのrbenvが先に採ったもので、[rbenvとは？Rubyバージョン管理の仕組みとRVMとの違い・1.3系の導入手順](https://www.issoh.co.jp/tech/details/7474/)とほぼ同じ考え方になります。

### PYENV\_VERSIONと.python-versionとglobalの解決順序

どの版が選ばれるかは、READMEに明記された次の優先順位で決まります。

| 優先 | 参照先                     | 設定するコマンド       | 効く範囲     |
| -- | ----------------------- | -------------- | -------- |
| 1  | `PYENV_VERSION` 環境変数    | `pyenv shell`  | そのシェル    |
| 2  | カレントの `.python-version` | `pyenv local`  | そのディレクトリ |
| 3  | 親の `.python-version`    | `pyenv local`  | 配下すべて    |
| 4  | `$(pyenv root)/version` | `pyenv global` | マシン全体    |

3番目が効くため、リポジトリのルートに `.python-version` を1つ置けば、その下のどこで作業しても同じ版になります。逆に、意図しない親のファイルを拾って版が変わることもある。何が効いているかは `pyenv version` で確かめられ、版名の後ろに「set by」として参照元のパスが出ます。なお `pip install black` のようにコマンドを増やすパッケージを入れた直後は、shimが未生成で command not found になるため `pyenv rehash` を回してください。

## macOSとUbuntuへpyenvを入れてシェル初期化まで通す手順

pyenvはPythonのバイナリを配布しません。`pyenv install` はソースを取ってきて手元でコンパイルします。Cコンパイラと開発ヘッダが先に揃っていないと動かない、導入で最も落ちやすい工程です。

### ビルド依存パッケージをUbuntuとmacOSで先に入れるコマンド

[pyenv Wikiの Suggested build environment](https://github.com/pyenv/pyenv/wiki)に、OSごとの推奨パッケージが列挙されています。Ubuntu系とmacOS（Homebrew）の記述は次のとおり。

```
# Ubuntu / Debian / Mint
sudo apt update; sudo apt install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl git \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev libzstd-dev

# macOS（Homebrew）
brew install openssl@3 readline sqlite3 xz tcl-tk@8 libb2 zstd zlib pkgconfig
```

この一覧を「念のため入れるもの」と受け取らないでください。`libsqlite3-dev` が無ければ `sqlite3` が、`liblzma-dev` が無ければ `lzma` が、そのPythonから欠落します。ビルド自体は成功扱いで終わるため、気付くのは数週間後にimportした瞬間になる。先に全部入れるのが結果的に速い。

Wikiには制約も書かれています。Ubuntu 20.04では libzstd の版が古く、Python 3.14の `compression.zstd` のビルドに対応できません。Alma / Rocky Linux 8 も同様。古いOSの上で最新のPythonを建てる構成は、この一点で詰まります。

### pyenv本体を取得する3経路とシェル設定へ書き足す3行の指定

本体の入れ方は3通りです。インストーラを使う `curl -fsSL https://pyenv.run | bash`、リポジトリを直接置く `git clone`、macOSなら `brew install pyenv`。git cloneはプラグインの追加や更新をgit操作で扱えます。次にシェル設定へ書く行が本題で、READMEのbash / zsh向けの記述は次の3行です。

```
# ~/.bashrc（zshなら ~/.zshrc）へ追記
export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init - bash)"
```

1行目でpyenvの置き場所を宣言し、2行目で `pyenv` 本体をPATHへ通し、3行目でshimsのPATH追加と補完を有効にします。zshなら3行目を `pyenv init - zsh` に変える。書き込む先はログインシェルの種類で変わります。[GitHubのReleases](https://github.com/pyenv/pyenv/releases)で確認できる最新版は v2.8.5（2026年9月1日公開）でした。

## pyenv installでPython本体を入れglobalとlocalで切り替える

シェル初期化まで通っていれば、あとはコマンド4つで運用が回ります。

### install –listから版を選んで入れる一連のコマンド

入れられる版の一覧は `pyenv install --list` で出ます。CPythonの各版に加えて、PyPy・GraalPy・Jython・Anaconda / Miniconda などが並ぶ。READMEにも複数のPython実装をサポートする旨が書かれています。

```
# インストール可能な版を絞って一覧
pyenv install --list | grep -E '^\s*3\.(13|14)\.'

# 特定の版をビルドして入れる（-v で進行を表示）
pyenv install 3.14.0

# 入っている版を確認（* が現在有効な版）
pyenv versions

# 使わなくなった版を消す
pyenv uninstall 3.11.9
```

ソースからのコンパイルなので、1版あたり数分から十数分かかります。CIのように毎回作り直す用途には向きません。

### globalとlocalとshellの3階層を使い分ける指定

切り替えは範囲の違う3つのコマンドで行います。狭いほうが強い優先順位はさきほどの表のとおり。

```
# マシン全体の既定を決める（$(pyenv root)/version に書かれる）
pyenv global 3.14.0

# このディレクトリ配下だけ固定する（.python-version が作られる）
cd ~/work/legacy-batch
pyenv local 3.10.14

# いま開いているシェルだけ一時的に変える（PYENV_VERSION を設定）
pyenv shell 3.13.7
pyenv shell --unset

# どの版が効いていて、どこで決まったかを見る
pyenv version
pyenv which python
```

`pyenv local` で生成される `.python-version` は版名が1行入るだけのプレーンテキストです。これはリポジトリへコミットしてください。cloneしただけで同じ版に揃います。uvも同じファイル名を読むため、後でuvへ移す際の足場にもなる。`pyenv local 3.14.0 3.13.7` と複数書けば前者が優先されつつ両方が探索対象になり、toxから複数版を叩けます。

## BUILD FAILEDで止まったときにビルド依存を切り分ける手順

pyenvで最も相談が多いのがここです。エラーメッセージだけでは原因が分からないため、切り分けの順番を決めます。

### BUILD FAILEDのログを読む位置と一次切り分けの順番の決め方

`pyenv install` が落ちると、末尾に `BUILD FAILED` と一時ディレクトリのログパスが出ます。読むべきはログの末尾ではなく、`The necessary bits to build these optional modules were not found` の周辺です。[Common build problems](https://github.com/pyenv/pyenv/wiki/Common-build-problems)にOSと症状ごとの対処が集まっており、まずここで自分のメッセージを検索するのが早い。

順番としては、第1にWikiのビルド依存を全部入れ直して再実行する。第2に狙う版がそのOSとCPUアーキで対応しているかを見ます。3.8以前の古いPythonを新しいglibcの上でビルドすると、当時のソースが現行のツールチェーンに対応しておらず落ちる。第3にディスク容量を確認します。

### ビルドが通ったのにsqlite3やlzmaがimportできない症状

厄介なのはこちらです。`pyenv install` は成功し、`python` も起動する。ところが `import sqlite3` だけが `ModuleNotFoundError` になる。ビルド時に対応する開発ヘッダが無く、その拡張モジュールだけスキップされた状態です。Wikiが「システム依存関係が満たされていない場合、ビルド成功後の実行時に予期しない障害が生じる」と警告しているのがこれ。

```
# 欠落しているモジュールを一括で洗い出す
for m in sqlite3 lzma bz2 ssl ctypes readline curses zlib tkinter; do
  python -c "import $m" 2>/dev/null && echo "OK   $m" || echo "MISS $m"
done
```

MISSが出たら、対応する開発パッケージ（`sqlite3` なら `libsqlite3-dev`）をOS側へ入れてから、その版を `pyenv uninstall` して入れ直します。後から足したヘッダは既存のビルド結果に反映されないため、再ビルドが必要です。新しい版を入れた直後に1回回しておけば、数週間後に気付く事態を避けられる。

## pyenv-virtualenvとvenvを重ねて依存を分離する構成の選び方

pyenvが分けるのは版だけで、入れたパッケージは同じ版を使うプロジェクト間で共有されます。依存を切りたいなら、もう1層かぶせる必要がある。

### pyenv virtualenvで作った環境を版名として扱う操作の手順

[pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv)は、virtualenvとconda環境をpyenvの管理下に置くプラグインです。作った環境は `$(pyenv root)/versions` の下に置かれ、`pyenv versions` の一覧に版と並んで出る。`pyenv local` の指定先に環境名をそのまま書けます。

```
# プラグインを入れる（Homebrewなら brew install pyenv-virtualenv）
git clone https://github.com/pyenv/pyenv-virtualenv.git \
  "$(pyenv root)/plugins/pyenv-virtualenv"

# シェル設定へ追記（pyenv init の行の後ろ）
eval "$(pyenv virtualenv-init -)"

# 3.14.0 をベースに myapp という環境を作る
pyenv virtualenv 3.14.0 myapp

# このディレクトリに入ったら自動で myapp が有効になる
pyenv local myapp

# 手動で切り替える場合
pyenv activate myapp
pyenv deactivate

# 一覧と削除
pyenv virtualenvs
pyenv virtualenv-delete myapp
```

内部実装は状況で変わります。READMEには `python -m venv` が使えて `virtualenv` が無い場合は前者を使う、conda環境があるなら `conda create` を優先する、という記述がある。ベースが現行のPythonなら実質 `venv` が動いています。

### venvだけで足りる場面とプラグインを入れるべき場面の線引き

プラグインを入れずに `python -m venv .venv` だけで済ませる構成でも、依存の分離は達成できます。差が出るのは切り替えの手数です。`pyenv local myapp` を書いておけば `cd` した時点で環境が有効になり、`source .venv/bin/activate` を叩き忘れてグローバルへパッケージを入れる事故が消える。

逆に `.venv` をプロジェクト直下に置く方式は、IDEが自動検出しやすく、ディレクトリを消せば環境も消えます。チームに配る前提なら `.venv`、手元で20も30も抱えるならpyenv-virtualenv、という分け方が現実的です。どこまで分けるかは[仮想環境とは？venv・コンテナ・仮想マシンの違いと隔離レベルの選び方](https://www.issoh.co.jp/tech/details/13536/)で決めてください。

## WindowsでWSLとpyenv-winのどちらを選ぶかを決める基準

Windowsで検索してたどり着いた場合、まずここを読んでください。本家pyenvは動きません。

### pyenv-winの導入手順とPATHへ通す2つのディレクトリ

READMEには「pyenvはWindowsを公式にサポートしておらず、Windows Subsystem for Linuxの外では動作しない」と明記されています。代替として案内されているのが[pyenv-win](https://github.com/pyenv-win/pyenv-win)、@kirankotari によるWindows移植版です。

```
# PowerShellでインストーラを取得して実行
Invoke-WebRequest -UseBasicParsing `
  -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" `
  -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"
```

インストール後、ユーザー環境変数のPATHへ `%USERPROFILE%\.pyenv\pyenv-win\bin` と `...\shims` の2つを通します。前者が `pyenv` コマンド本体、後者がshim。Git・Zip手動・pip・Chocolateyでの導入もリポジトリに案内があります。

選択の基準はシンプルです。開発対象がLinux上で動くなら、WSL2の中に本家pyenvを入れてください。改行コード・パスの区切り・シェルスクリプトの挙動が本番と揃います。WSL側の準備は[WSLで開発環境を構築する手順｜.wslconfig調整とDocker連携・肥大化の対処](https://www.issoh.co.jp/tech/details/17354/)にまとめました。ネイティブ実行が要る場合だけ、pyenv-winを選ぶ。

## pyenvとuv・Poetry・condaの役割の重なりを実装で切り分ける

Python環境まわりのツールは層が違うのに名前が似ていて、どれを入れるか分からなくなります。層で切ると迷いません。

### uvがソースビルドを避けて秒で入る仕組みとpyenvとの構造差

uvはPythonの版管理とパッケージ管理を1つのコマンドに束ねたツールです。pyenvとの決定的な差はPythonの入手経路にあります。[uv公式のInstalling Python](https://docs.astral.sh/uv/guides/install-python/)には、uvが配布するPythonはAstralの python-build-standalone プロジェクトのディストリビューションであり、Python本体が公式の配布可能なバイナリを出していないためこの方式を採る、と説明されています。

つまりuvは事前ビルド済みのバイナリを展開するだけで、コンパイルしません。ビルド依存を揃える工程も、BUILD FAILEDの切り分けも、`libsqlite3-dev` の欠落も発生しない。必要になった時点で版を自動ダウンロードするとも書かれており、`uv python install` でpyenvと同じ操作が置き換わります。pyenvが残るのは、python-build-standaloneが提供していない実装や古い版を建てる場合と、ビルドオプションを指定する場合。uv側の全体像は[uvとは？Pythonの環境構築・パッケージ管理・バージョン管理の使い方を徹底解説](https://www.issoh.co.jp/tech/details/4384/)で扱っています。

### Poetryとcondaが担う層とpyenvだけに残る用途の切り分け

層を並べると重なりが見えます。

| ツール    | Python本体の版 | 仮想環境     | 依存解決とロック        | 非Pythonのライブラリ |
| ------ | ---------- | -------- | --------------- | ------------- |
| pyenv  | ソースからビルド   | プラグインで対応 | 対象外（pipに任せる）    | 対象外           |
| uv     | 事前ビルド版を取得  | 自動で作る    | uv.lock         | 対象外           |
| Poetry | 対象外        | 自動で作る    | poetry.lock     | 対象外           |
| conda  | チャネルから取得   | 自動で作る    | environment.yml | 扱える           |

Poetryは版管理を持たないので、pyenvやuvと組み合わせて使う位置にあります。選定の考え方は[Poetryとは？Python依存管理の仕組みと2.4系の使い方・uvとの選定基準](https://www.issoh.co.jp/tech/details/12303/)にまとめました。

condaは毛色が違う。CUDAやMKLといった非Pythonのバイナリまで同じ仕組みで配れる点が独自で、機械学習や科学計算で選ばれる理由がそこにあります。pipとcondaを混ぜると依存が壊れやすい注意も含めて、[pipとcondaの違いと使い分け｜Anaconda・Miniconda・商用ライセンスまで解説](https://www.issoh.co.jp/tech/details/7775/)で整理しています。

## 受託開発でpyenvを採用する条件と、CIやDockerで見送る場面

判断の章です。pyenvを入れる側・入れない側の境界だけを条件で書きます。

### EOL版に固定された既存システムを触るときにpyenvが効く条件

採用してよいのは、次の2条件のどちらかが成立するときです。第1に、既存システムがサポート切れ間近のPython版に固定されている場合。[Python公式のStatus of Python versions](https://devguide.python.org/versions/)によれば、3.9は2025年10月31日でend-of-lifeを迎え、3.10から3.12はセキュリティ修正のみ、バグ修正が続いているのは3.13と3.14です。3.10のサポート終了は2026年10月と示されており、2026年9月時点では目前。手元に3.10と3.14を並べて挙動を比べられる状態が、この局面で効きます。

第2に、CPython以外の実装を並べる必要がある場合。`pyenv install --list` にはPyPy・GraalPy・Jythonが並び、実装をまたいだ挙動比較がコマンド1つで済む。事前ビルド版を配る方式では、この幅は出せません。なおEOL版のシステムを新しい版へ寄せる作業は、版を上げるだけでは終わりません。依存ライブラリの対応状況、削除された標準モジュールの置き換えを洗い出す工程が前段に要ります。一創ではこの種の移行を[システムマイグレーション・リプレイス](https://www.issoh.co.jp/service/system/migration/)として、影響範囲の調査から段階的な切り替えまで請け負っています。

### CIとDockerではpyenvを使わずベースイメージに寄せる判断

見送るべき場面は2つ。1つ目はCIです。pyenvはソースからビルドするため、ジョブごとに数分から十数分をコンパイルに使う。キャッシュの細工を足すくらいなら、公式のセットアップアクションへ替えたほうが速い。

2つ目はDockerです。コンテナの中でpyenvを動かす構成は、イメージが太り、ビルド時間が延び、レイヤの再利用も効きにくくなる。`FROM python:3.14-slim` のように版をベースイメージで指定すれば、版の固定はそれだけで達成されます。コンテナは1イメージに1つのPythonという前提で作るものなので、複数版を共存させる道具を中に入れる理由がありません。新規構築でも同じで、pyenvを選ぶ理由は「既存の何かに合わせる必要があるか」に集約されます。

## よくある質問

導入時に挙がる質問を、公式ドキュメントの記述に沿って整理しました。

### pyenvはWindowsで使えますか？

本家pyenvは使えません。READMEに「Windowsを公式にサポートしておらず、WSLの外では動作しない」と明記されています。選択肢は、WSL2の中に本家pyenvを入れるか、移植版のpyenv-winを入れるかの2つ。開発対象がLinux上で動くならWSL2、ネイティブ実行が要件に入っている場合だけpyenv-winを選びます。

### pyenvとuvはどちらを使うべきですか？

新規に始めるならuvです。uvはPythonを事前ビルド版として取得するため、ビルド依存の準備もBUILD FAILEDの切り分けも発生しません。pyenvを選ぶ理由は2つ。python-build-standaloneが出していない版や実装を手元で建てる場合と、ビルドオプションを自分で指定する場合です。既存プロジェクトが `.python-version` で運用されているなら、そのファイルはuvも読むため移行の足場になる。

### pyenv installが失敗するときは何を見ればよいですか？

Wikiのビルド依存パッケージを全部入れ直してから再実行するのが最初です。ログの「necessary bits」の行に欠けているモジュール名が出ます。解決しない場合はCommon build problemsでメッセージを検索してください。3.8以前の古いPythonを新しいOSの上でビルドして落ちるケースもあり、その場合は狙う版を上げるか、コンテナで当時のOSを再現する。

### globalとlocalとshellはどう使い分けますか？

効く範囲が違います。`pyenv global` はマシン全体の既定で、`$(pyenv root)/version` に書かれる。`pyenv local` はカレントに `.python-version` を作り、配下すべてに効きます。`pyenv shell` は開いているシェルだけを変える。優先順位はshell・local・globalの順です。

### pyenvを入れたのに版が切り替わらないのはなぜですか？

PATHの順序を確認してください。`which -a python` を実行し、`.pyenv/shims/python` が先頭に出ているかを見ます。他のツールがPATHの先頭へシステムのPythonを差し込んでいると、shimに届きません。順序が正しいのに切り替わらない場合は `pyenv version` の「set by」に出る参照元のパスを見る。意図しない親の `.python-version` を拾っていることがあります。

## 関連記事

- [uvとは？Pythonの環境構築・パッケージ管理・バージョン管理の使い方を徹底解説](https://www.issoh.co.jp/tech/details/4384/)
- [Poetryとは？Python依存管理の仕組みと2.4系の使い方・uvとの選定基準](https://www.issoh.co.jp/tech/details/12303/)
- [仮想環境とは？venv・コンテナ・仮想マシンの違いと隔離レベルの選び方](https://www.issoh.co.jp/tech/details/13536/)
- [pipとcondaの違いと使い分け｜Anaconda・Miniconda・商用ライセンスまで解説](https://www.issoh.co.jp/tech/details/7775/)
- [WSLで開発環境を構築する手順｜.wslconfig調整とDocker連携・肥大化の対処](https://www.issoh.co.jp/tech/details/17354/)

---

出典: [pyenvでPythonのバージョンを切り替える手順｜shimの仕組みとビルド失敗の対処](<https://www.issoh.co.jp/tech/details/17513/>)（株式会社一創）
