🐍

[python初心者] 仮想環境venvのことを調べました

2024/02/03に公開

venvとは

pythonで仮想環境を作るためのモジュール
Python3.3以降で標準ライブラリの一部になった

なぜ仮想環境必要か

仮想環境は、プロジェクトごとに異なるパッケージやパッケージバージョンを管理するために使用される。
システム全体のPythonインストールを変更せずに、プロジェクト固有の依存関係を維持することができる。

javascript/node.jsのpackage.jsonがあって、インストールして関連パッケージがnode_modulesに格納されると同じイメージ

仮想環境基本コマンド

前提としてPythonがシステムにインストールされていること
つまりpythonまたはpython3コマンドを実行できること

仮想環境の作成

現在ディレクトリ位置から仮想環境作成する

python -m venv venv

基本はプロジェクトリポジトリー配下で作成
フロントエンド・バックエンドが同じリポジトリーにある場合はcd backendなどしてバックエンドディレクトリ配下に移動してから

-mは、モジュールをコマンドラインから直接実行できるようにするためのオプション
1つ目のvenvはモジュールの名前を指し
2つ目のvenvは仮想環境の名前で、任意の名前を指定できるが、ほとんどの記事でみかけるのはそのままvenvの名前で仮想環境作っているようです

例えば

python -m venv myenv

とか任意の名前でもオッケーは仮想環境の名前ですが、任意の名前に置き換えることができます。

仮想環境のアクティベート

dockerのコンテナーを立ち上げてないと使えないように、venv仮想環境も使うのにアクティベートが必要
アクティベートすると、その仮想環境内でインストールされているPythonとパッケージが使用されるようになる

  • Windows:
venv\Scripts\activate
  • macOS と Linux:
source venv/bin/activate

仮想環境でのパッケージ管理

仮想環境がアクティベートされたら、pipを使用してパッケージをインストール、アンインストール、またはアップグレードできる

たとえば、requestsパッケージをインストールする

pip install requests

仮想環境の非アクティベート

アクティベートされている仮想環境から出るためのコマンド

deactivate

仮想環境出たら、またシステムのグローバルPythonインストールに戻っていることになる

仮想環境の削除

あまりやらないかもだが、仮想環境がアクティベートでないときに、ディレクトリを削除すればそれだけで済む話
node_modulesディレクトリまるごと削除してpackage.jsonからインストールし直すみたいなイメージで
venvディレクトリをまるごと削除すれば仮想環境は削除される
さてpythonの仮想環境をインストールしなおそうと思うと、package.jsonに相当するrequirements.txtが必要

requirements.txtのこと

必要なパッケージを記録して再利用できる

仮想環境を作ってアクティベートするだけでは、pythonの標準ライブラリしか使えないので、仮想環境内でpip installして都度必要なパッケージをインストールする
だけどpip installしただけでは、その仮想環境内にどんなパッケージがインストールしているかわからない
インストール済みのパッケージを記述するのはrequirements.txtのことで
アクティベートの状態で

pip freeze > requirements.txt

でrequirements.txtが作られる
requirements.txtには、現在の仮想環境にインストールされている全てのパッケージと、それらの具体的なバージョンが記載されている

venvを削除してインストールしなおすときは、ほかの他の開発者が同じ環境を再現するとき

pip install -r requirements.txt

でパッケージがインストールできる

仮想環境作りたてのとき

python -m venv venv
source myenv/bin/activate
pip freeze > requirements.txt

これは空のrequirements.txtが作られるだけ
まだ何もパッケージインストールしてないので

そこからpip installしても、requirements.txtが空のまま

pip installしただけでは自動で記録されない

毎回手動でpip freeze > requirements.txtする必要がある

シェルスクリプトでpip installpip freeze > requirements.txtを一緒に実行するようにする

touch pipf.sh
pipf.sh
#!/bin/bash
pip install "$@"
pip freeze > requirements.txt

シェルスクリプトに実行権限与える

chmod +x pip_install.sh

それでインストールするときは

./pipf.sh hogehoge

でpip installとpip freezeを両方やってくれる

参考記事
https://zenn.dev/arsaga/articles/0fdee431a8374a

仮想環境外でpip installやってしまっていた

仮想環境をアクティベートせずにpip installコマンドを実行した場合、パッケージはシステムのグローバルPython環境にインストールされてしまう

これは複数プロジェクトのパッケージ依存関係に競合が発生したり、プロジェクトの環境の再現が難しくしたりと、多くの不都合をきたすので基本やらない
仮想環境を使うのが基本

だけどvenvのことわからないままpip installをすでにいろいろやっちゃったのでちょっと整理しようと

グローバルでインストールされているパッケージを確認

仮想環境がアクティベートされていない状態で

pip list

インストールされているパッケージの名前とバージョンのリストが表示される
リストには、Pythonの標準ライブラリに含まれない、pipを使用してインストールされたパッケージが含まれる

システムに複数python環境があると、それぞれのリストがある
例えば

pip3 list

pythonをインストールしただけの状態では、pip, setuptools, wheelなどの基本パッケージしかないようですが、自分のローカル環境でpip listやってみたら長いリストでてきた。。。
うん。。。何年もわからないままpip installやっちゃってるもんね。。。

グローバルにインストールすべきじゃないものを削除

全部削除して動かなくなったのも大変なので、とりあえず現状のリストを保存する

pip list --format=freeze > installed_packages.txt

とりあえずこれでinstalled_packages.txtに保存されるので、requirements.txtと全く同じで最悪インストールしなおせばいい

installed_packages.txtの確認して、必要なパッケージ以外全部アンイストールする

grep -vE "pip|setuptools" installed_packages.txt | xargs pip uninstall -y

必要かどうかの判断は難しくて、全部削除するのが怖い、という場合は、パッケージごとの依存関係は調べられるので、絶対グローバルじゃなくていいものを手動で削除する

pip show <package-name>

で依存パッケージしらべられる

例えばgspreadというパッケージは特定のプロジェクトしか使わないと分かっているので

% pip show gspread
Name: gspread
Version: 5.12.3
Summary: Google Spreadsheets Python API
Home-page: 
Author: 
Author-email: Anton Burnashev <fuss.here@gmail.com>
License: 
Location: /Users/hogehoge/.anyenv/envs/pyenv/versions/3.11.2/lib/python3.11/site-packages
Requires: google-auth, google-auth-oauthlib
Required-by:

とgspreadと一緒にgoogle-auth, google-auth-oauthlibも削除できるとわかる

万一グローバルパッケージの削除でトラブったら

pip install -r installed_packages.txt

でインストールし戻す

pip list --format=freezepip freeze違い

作成されたrequirements.txtとinstalled_packages.txtをみる限りほとんど一緒
実際ほとんど一緒

pip freeze: 依存関係の記録や共有に特化している
pip list --format=freeze: より汎用的な pip list コマンドの出力形式の一つ

pip list --format=freeze > installed_packages.txt

pip list コマンドはインストールされているパッケージをリストアップ
--format=freeze オプションは出力フォーマットを指定して、結果pip freeze と同様の出力を生成している

作ったinstalled_packages.txtは、作成される時点のPython環境(グローバルまたは仮想環境)にインストールされている全てのパッケージのスナップショットで、デバッグや環境の完全な復元、ドキュメント化の目的で使用される

pip freeze > requirements.txt

pip freeze コマンドは、現在の環境にインストールされているパッケージとそのバージョンを パッケージ名==バージョン の形式で出力
もっぱらプロジェクトの依存関係を requirements.txt ファイルに保存するためのコマンド

pip freezeで作ったrequirements.txtは、特定のプロジェクトの依存関係を定義するために使用され、常は、プロジェクトの実行に絶対に必要なパッケージのみを含む。
つまり開発者が意図的に選択したものをリストアップしていることになります

まあ、ほとんど一緒で、なんならファイル名も任意でよかった
pip install -r hogehoge.txtコマンドはファイル名を引数で渡すので、内容が正しい形式であればどのような名前でも動く

名前は何でもよかったけど、慣例的にrequirements.txtを使っていて、Pythonプロジェクトにおける依存関係リストのための業界標準のようなもの
プロジェクトが複数の依存関係セットを持っている場合は、dev-requirements.txtやprod-requirements.txtなど、目的に応じて名前を変更することができる

installed_packages.txtはなんの目的かわからなくなるので、例えば、snapshot-2024-02-03.txtのように特定の日付を含めることで、いつこのスナップショットがわかるようにしたり

そもそもPythonの標準ライブラリに何が入ってる?

Pythonの公式ドキュメント参照
例えばpython 3.12.1の標準ライブラリは
https://docs.python.org/3.12/library/index.html

例えばこんなものが入ったりしてます

  • math: 数学関数
  • datetime: 日付と時刻の操作
  • os: オペレーティングシステムとのインタラクション
  • sys: Pythonインタプリタとその環境にアクセスするための関数と変数を提供
  • re: 正規表現による文字列処理
  • json: JSONデータの読み書き
  • http: HTTPと関連プロトコルを扱うためのモジュール群
  • unittest: ユニットテストのフレームワーク

と、標準ライブラリでも大量のパッケージが入っている

公式ドキュメントは標準ライブラリの各モジュールの使い方、関数、クラス、例外などについて詳細にかかれてある

まだまだ勉強するものが大量にある

Discussion