【Mac】仮想環境でTkinterが使えない!原因と解決手順

Pythonで勤怠管理アプリを作ろうとしたら、最初の import tkinter でエラーが出てしまいました。Anacondaでは使えていたのに、なぜ? 解決しようと進めると、今度は「Xcodeが古い」というエラーまで……Macが古すぎるのかと戸惑いました。

今回は、Xcode本体を更新せず、Tkinterが使えるようにPythonと仮想環境を作り直すことで解決できました。この記事では、MacでPythonを勉強中の私がつまずいたポイントと、実際に解決した手順を、用語の備忘録も交えながら紹介します。

この記事はこんな方におすすめです

  • Macで `No module named ‘_tkinter’` というエラーが出ている方
  • AnacondaではTkinterが使えたのに、pyenvやvenvの環境では使えず困っている方
  • Pythonの環境構築中に「Xcodeが古い」と表示され、戸惑っている方
  • Python・仮想環境・Command Line Toolsの関係を、実例を通して知りたい方

今回の環境と、この記事の対象

  • macOS:14.1.1
  • Python:3.11.15(pyenvで管理)
  • pyenv:2.8.2
  • 仮想環境:プロジェクト内の .venv
  • 確認できたCommand Line Tools:15.3
  • 用意したTcl/Tk:tcl-tk@8 8.6.18

※この記事は、私の環境で解決できた記録です。Homebrew版PythonやAnacondaでは対応が異なります。同じエラーでも、原因や必要な開発ツールは環境によって変わります。

最初のエラー:No module named ‘_tkinter’

最初に実行しようとしたのは、ウィンドウを表示するだけのコードです。

import tkinter as tk

window = tk.Tk()
window.title("勤怠アプリ")
window.geometry("480x640")
window.mainloop()

これを main.py として保存し、仮想環境を有効にして起動しました。

source .venv/bin/activate
python main.py

すると、次のエラーが出ました。

ModuleNotFoundError: No module named '_tkinter'

tkinter と _tkinter は少し役割が違います。Pythonのコードから使う入り口が tkinter、その裏側でTcl/Tkという画面表示の仕組みにつなぐ部品が _tkinter です。今回は後者が使えない状態でした。

TkinterはPythonの標準ライブラリですが、Pythonのインストール方法や、作られたときの環境によっては、この部品が含まれていないことがあります。

venvを有効にしたのに、別の場所のPythonを見ている?

エラーには、プロジェクトの .venv ではなく、次のような場所が表示されていました。個人名の部分は省略しています。

~/.pyenv/versions/3.11.15/lib/python3.11/tkinter/__init__.py

「仮想環境を有効にしたはずなのに?」と思いましたが、venvは元になるPythonを利用する仕組みなので、標準ライブラリの場所が .venv の外でも、それだけで異常とは限りません。

実行中のPythonと、その元になったPythonは、次のコマンドで確認できます。

python -c "import sys; print('実行中:', sys.executable); print('元のPython:', sys.base_prefix)"

AnacondaでTkinterが使えていたのも、今回のpyenvとは別のPython環境だったためです。別の環境で使えるライブラリが、今の環境でも使えるとは限らないのですね。

途中で「Xcodeが古い」という別のエラーも出た

Tcl/Tkを用意する過程で、Homebrewの python-tk@3.11 もインストールしようとしました。しかし、Xcode 14.3.1が古く、16.2への更新を求めるエラーが出て止まってしまいました。

ただ、あとから整理すると、python-tk@3.11 はHomebrew版Python向けのパッケージです。今回直したかったのはpyenv版のPythonなので、このインストールを通すことが解決の必須条件ではありませんでした。

そこで、Xcode本体を更新する前に、使用中の開発ツールを確認しました。

xcode-select -p

確認時の結果はこちらです。

/Library/Developer/CommandLineTools

バージョン情報も確認しました。

pkgutil --pkg-info=com.apple.pkg.CLTools_Executables

この環境には、Command Line Tools 15.3が入っていました。

XcodeはAppleのアプリ開発用の道具一式です。一方、Command Line Toolsは、ターミナルで開発するためのコンパイラーなどをまとめたもので、Xcode本体とは別にインストールできます。

今回は、Xcode本体を更新せずに、既存のCommand Line Toolsを使ってPythonを作れました。ただし、これは「古いXcodeがあっても、どんなPythonでも必ず作れる」という意味ではありません。作りたいPythonと、macOS・開発ツールの組み合わせによって結果は変わります。

解決手順① Tcl/Tk 8を用意する

ここからは、解決に使った手順を順番に整理します。コマンドはターミナルで実行します。

brew install tcl-tk@8

私の環境には最初、Tcl/Tk 9が入っていました。今回はPython 3.11.15で使うためにTcl/Tk 8を追加しました。

インストール状況は、次のコマンドで確認できます。

brew list --versions tcl-tk@8

ただし、Tcl/Tkを後から入れただけでは、すでにインストールされているPythonに不足していた部品が追加されるわけではありません。 続いてPythonを作り直します。

解決手順② 同じPythonを別の名前で作り直す

ターミナルの先頭に (.venv) が付いている場合は、いったん仮想環境を解除します。

deactivate

元のPythonは残し、Tkinter用に別の名前でインストールしました。以下は、使うTcl/Tkを明示する設定も含めたコマンドです。

PYTHON_BUILD_HOMEBREW_TCLTK_FORMULA=tcl-tk@8 \
pyenv install 3.11.15:3.11.15-tk

1行目でHomebrewの tcl-tk@8 を指定しています。行末の \ は、コマンドが次の行に続くという意味です。2行をまとめて実行します。

3.11.15:3.11.15-tk は、「Python 3.11.15を、3.11.15-tkという名前でインストールする」という指定です。末尾の -tk は区別のための名前で、正式なバージョン番号ではありません。

私の場合、ログに次の表示がありました。

python-build: use tcl-tk@8 from homebrew

その後、3.11.15-tk へのインストールが完了しました。Python自体を新しいバージョンにしたのではなく、同じ3.11.15を、Tkinterが使える構成で作り直したことになります。

解決手順③ 新しいPythonでウィンドウを確認する

まずは仮想環境を作り直す前に、新しく用意したPythonを直接指定して確認しました。

"$(pyenv root)/versions/3.11.15-tk/bin/python" -m tkinter

$(pyenv root) は、pyenvの保存場所を取得する部分です。-m tkinter は、Tkinterの確認用プログラムを実行する指定です。

このコマンドで、小さな確認用ウィンドウが開きました! インストールのコマンドだけではウィンドウは開かないので、この確認は別に行います。

解決手順④ プロジェクトのvenvを作り直す

新しいPythonで動いても、既存の .venv は以前のPythonを元に作られたままです。source .venv/bin/activate だけでは、新しいPythonに切り替わりません。

ここからは、main.py と .venv があるプロジェクトのフォルダで作業します。仮想環境が有効なら、先に deactivate を実行します。

すでにライブラリを入れている場合は、作り直す前に一覧を控えておくと再インストールに役立ちます。次は任意の追加手順です。

.venv/bin/python -m pip freeze > requirements-before-rebuild.txt

古い仮想環境は、すぐに消さずに名前を変えて残しました。.venv-backup がすでにある場合は、別の未使用の名前にしてください。

mv .venv .venv-backup

Gitで管理している場合は、バックアップも公開しないように .gitignore に追加しておきます。

.venv/
.venv-backup/

次に、Tkinterが使えるPythonを明示して、新しい仮想環境を作ります。

"$(pyenv root)/versions/3.11.15-tk/bin/python" -m venv .venv

新しい仮想環境を有効にします。

source .venv/bin/activate

元のPythonを確認すると、パスの末尾が 3.11.15-tk になっていました。

python -c "import sys; print('実行中:', sys.executable); print('元のPython:', sys.base_prefix)"

新しい仮想環境には、古い環境の追加ライブラリは引き継がれません。今回の最小コードはTkinterだけなので追加インストール不要でしたが、ほかのライブラリを使っているアプリなら再インストールします。一覧を保存した場合は、内容を確認してから次のように利用できます。

python -m pip install -r requirements-before-rebuild.txt

最後に、仮想環境の中で確認してからアプリを起動します。確認用ウィンドウを閉じたあと、次のコマンドへ進みます。

python -m tkinter
python main.py

これで、勤怠アプリのウィンドウも無事に表示できました。

必要なライブラリやアプリの動作を確認できたら、古い .venv-backup は削除できます。私はエディターのファイル一覧から削除しました。今使っている .venv と間違えないようにします。

なお、名前を変えた仮想環境は、そのまま別名で動かすためのものではなく、今回は復旧用に退避したものです。main.py などの自分のコードは、仮想環境のフォルダ内には置かないようにします。

今回分かったこと

最初は「Macが古いから、もうTkinterは使えないのかな」と思いました。でも、今回直接困っていたのは、使っているPythonに必要な部品が入っていなかったことでした。

解決までには、Python、pyenv、venv、Tcl/Tk、Xcode、Command Line Toolsと、いろいろな名前が出てきました。正直、一度で全部理解するのは難しいです。笑

それでも、「どのPythonで動かしているのか」と「そのPythonで作った仮想環境なのか」を確認することが大事だと分かりました。

この作業を、アプリを起動するたびに繰り返す必要はありません。これからはプロジェクトのフォルダで、いつもの2つのコマンドで進められます。

source .venv/bin/activate
python main.py

ようやく、勤怠アプリの画面づくりに進めそうです!

参考にした公式ドキュメント