【Python】なぜ仮想環境が必要なのか（初心者向け）

# 仮想環境とは？
基本的にPython開発では開発PCの中に仮想的な開発環境を構築し、仮想環境上で開発を行います。
この仮想環境は1台のPCに複数構築することが可能で、成果物などに応じて切り替えて使用します。
![{C80FC9C0-BAEC-466F-912D-916844E243A3}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920588/5ec3e7a2-5ecc-22c9-c974-5ed633c79613.png)



# なぜ仮想環境が必要なのか
まず仮想環境を使用するうえで一番直感的に理解しやすいパターンから考えていきましょう。

### 複数プロジェクトに携わる例
例として`Developer B`が複数のプロジェクト開発に携わっている場合について考えます。
![{8DB322C2-7CBE-4CA9-B8AE-DE80F05C6B60}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920588/fe02058e-3b11-7884-22fe-859f14b52f2a.png)

どちらのプロジェクトでも`Library A`を使用した開発となっていますが、バージョンが違いますね。
両方とも`Developer B`が開発を行いますが、プロジェクトごとにPCを分けられるような贅沢な環境ならまだしも、一般的には1台のPCで開発することが求められます。

このような場合に仮想環境を使うことで上手いことできるようになります。
![{24C12DF7-CF32-4466-B2A1-D8ECF51020CF}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920588/fe3aedb7-4fa1-31e7-cb65-47919eedd386.png)

1.　開発PCに`Project_A`という仮想環境を構築する。
2.　仮想環境`Project_A`に対して`Library A ver1.0`をインストールする。
3.　開発PCに`Project_B`という仮想環境を構築する。
4.　仮想環境`Project_B`に対して`Library A ver2.0`をインストールする。

それぞれの仮想環境は独立していますから、お互いのプロジェクトに対して影響しあうことなく開発ができるようになりました。

ではこのようなパターンでしか仮想環境を使わないのか？と言われるとそうではありません。
Pythonを使った開発では基本的に仮想環境を構築するものと考えてください。

## 仮想環境を構築する必要性について

仮想環境を構築するメリットは大きく分けて以下の4つにあると考えています。
1. 複数プロジェクトを管理しやすい
2. 目的に対して必要最低限のライブラリに限定することができる
3. ライブラリのリビジョン管理ができる
4. 開発環境を複数人で共有しやすい

上記1に関しては先ほど例に挙げたものですね。
以降のメリットには、`依存ライブラリ`というものが関係してきます。

:::note info
[依存ライブラリとは](https://qiita.com/Magurou/items/df43d6b572ec2ed904e0)

</details>
:::

### 必要最低限のライブラリに限定
1つのライブラリをインストールする場合でも複数の依存ライブラリも併せてインストールされるわけですが、仮想環境を使用せず同じ開発環境をずっと使い続けた場合はどうなるでしょうか。
![{FF787737-EBD8-4FC4-B9BA-A62D3881AAFC}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920588/254bf131-6333-21a7-4fa0-b1e6638d3c7f.png)


上記例の場合、`Application C`に必要なのは`Library C`のみですが他のアプリ開発時に使用したライブラリも混在している状態になります。

`Application C`を納品するうえで不要なライブラリが大量に含まれた状態で提供すると実行ファイルのサイズが爆発的に膨れ上がります。
それに伴って処理速度の低下も招くため成果物の品質を著しく低下させることになります。

それ以外にも、不要なライブラリが多いと依存ライブラリの競合によるエラーが発生する可能性も上がります。
ライブラリ同士が邪魔をし合って意図した挙動とは異なる動きをするためです。

例えば以下の例の場合、`Library B`は`Library A`の**ver 1.0**に依存しており、
`Library C`は`Library A`の**ver 2.0**に依存している状態です。
この`Library B`と`Library C`の両方が開発環境に入っており、`Library B`を使いたい場合について考えます。

![{00F7F8A6-7BEA-481C-B774-3FA35D0C76EE}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920588/5a9e3084-aa32-2ea4-27dd-cff521de0f51.png)


`Library B`が依存している処理が`func A`の場合は**ver 2.0**でも修正されていないため特に問題はありませんが、`func B`の処理に依存している場合は**ver 2.0**で更新されているため正常に動作しない可能性がありますよね。
**ver 1.0**の`func B`の挙動を前提として`Library B`が作られているのに、`Library C`があるせいで**ver 2.0**が採用されていたりでもしたら自分が書いたソースコードに異常がないのに`Library B`側でエラーになったりするわけです。
きちんと仮想環境を構築した場合でもライブラリの相性によっては事態が避けられないこともありますが、`Library C`が成果物に不要なものであった場合、無意味な事故を招くことになります。

もちろん1つの開発環境を使いまわす際に開発環境をリセットするのであれば、この点においては仮想環境を構築しているのと変わりませんからそれでも問題ありませんが、依存ライブラリも含めて正確にリセットする手間を考えれば仮想環境を作ってしまったほうが遥かに楽で事故も少ないですよね。

### ライブラリのリビジョン管理
誤って不要なライブラリをインストールしてしまった場合、依存ライブラリも含めて更新がかかるため悲惨なことになります。
そうでなくても開発途中で新しくライブラリをインストールした際に、今まで動いていた機能が動かなくなったりした場合、原因は追加したライブラリにあることが多いのですが、これを元に戻すのも地獄です。

こういった場合、仮想環境の構築方法にもよりますが、ライブラリの変遷をリビジョンとして記録してくれる機能があります。
![{7CF0EDEC-FB59-4613-859A-D40E420798A2}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920588/8865a25f-39c9-9113-5dbd-5ea6edf3766a.png)
画像赤枠内に`rev`と書かれていますがこれがリビジョンを表しています。
最初に仮想環境を構築した時が`rev 0`となっていて、そこからライブラリを更新するたびにリビジョンが上がって記録されます。

戻したいリビジョン番号を指定してインストールしなおすコマンドもあるので、それを使えば依存ライブラリも含めて簡単かつきれいに元通りにできるんです。凄いですよねぇ。
![{B7E9CA46-F637-4CFB-A5F6-4DC0997EF3C5}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920588/16d07a02-d84f-29c3-e167-d1ea013a900c.png)

### 複数人で開発環境を共有
仮想環境用のツールではインストール済みのライブラリを外部ファイルに出力する機能と、外部ファイルを元にライブラリをインストールする機能が用意されています。

そのため開発者が複数人いる場合に、先行して環境構築を行った人の仮想環境と同じ環境を他の開発者にも簡単に提供できるというわけです。


# まとめ
最後までご覧いただきありがとうございました。
今回は仮想環境の必要意義について私なりの解釈を図説多めで語ってみました。
Pythonに限らず様々な言語で仮想環境構築の概念は必要になりますので
その一助になれたら幸いです。