2022年度版Python環境構築徹底解説

この記事は[Nuco Advent Calendar 2022](https://qiita.com/advent-calendar/2022/nuco)の24日目の記事です

# はじめに

2022年最新のPython開発環境・プロジェクト構造についての紹介記事です。
現在のデファクトスタンダードと言えるツール群と、その簡単な使い方紹介していきますので、これからPythonで何かを作りたい人は、ぜひ参考にしてもらえると嬉しいです。

:::note
ここでいう**デファクトスタンダード**は、「公式に認められているかどうかに関わらず、事実上の標準として認知されているもの」という意味合いで用いています。
最も多く利用されているだけでなく、今後そうなっていくと考えられる、成長も十分に期待できるツール群を選択しています。
:::

# Pythonプロジェクト開発ツール デファクトスタンダードセット

|求める機能|スタンダードツール|
|:-:|:-:|
|[エディタ](#エディタ)|[Visual Studio Code](#visual-studio-code)|
|[バージョン管理](#バージョン管理ソフト)|[pyenv](#pyenv)|
|[パッケージ管理<br>仮想環境管理](#パッケージ管理・仮想環境管理)|[Poetry](#poetry)|
|[Linter](#linter)|[flake8](#flake8)|
|[Formatter](#formatter)|[Black](#black)|
|[単体テスト](#単体テスト)|[pytest](#pytest)|
|[型定義](#型定義・解析)|[typing](#typing)|
|[型解析](#型定義・解析)|[mypy](#mypy)|
|[テスト・解析管理](#テスト・解析管理)|[Nox](#nox)|
|[テスト自動化](#テスト自動化)|[pre-commit](#pre-commit)|


各機能とツールについて、説明していきます。

### エディタ

#### Visual Studio Code

エディタやIDE(統合開発環境)は好きに選んでいただければ良いとは思いますが、特に希望がないならば、Visual Studio Codeを選んでおけば間違いないでしょう。
Pythonを含む幅広い言語に対応し、豊富な拡張機能を備えている非常にリッチなエディタです。とりわけPythonプロジェクトについては、これさえ有れば、特にIDEなどは必要ないと思います。

インストールは↓から。

https://code.visualstudio.com/

### バージョン管理ソフト

Python3系は日夜アップデートされていて、2022年12月現在の最新verは、3.11.1が提供されています。
とはいえ、プロジェクトによっては、3.7.1までしか動作が担保されていないもの、3.9.0で現在開発中のもの...などがあります。最新のPythonが常に必要、というわけでは決してなく、過去のバージョンのPythonを自由に使い分けられる方が、利便性は高いです。

そこで必要になってくるのが、利用したいバージョンごとにPythonインタプリタを自由に切り替えることのできるバージョン管理ソフトです。

#### pyenv

https://github.com/pyenv/pyenv

最も有名なPythonのバージョン管理ソフトです。

pyenvを使うと、一つのマシン上で、複数のバージョンのPythonを使い分けることができます。
pyenvを経なくても直接Pythonをインストールすること自体は可能ですが、直接インストールすると、そのマシンで使えるPythonは、そのインストールしたバージョンのみに限られてしまいます。
インストールしたものと異なるバージョンのPythonを使わなければならない場合、今のPythonをアンインストールし、新しく必要なバージョンのPythonをインストールする必要が生じます。とても面倒ですね。

pyenvを使えば、都度使いたいバージョンをインストール→プロジェクトごとにバージョンの異なるPythonを使い分ける、という操作ができるようになります。

##### インストール

pyenvのGithubに各OSごとのインストール方法が書かれています。

https://github.com/pyenv/pyenv#installation

macならば、Homebrewでコマンド一発です。

```sh
brew install pyenv
```


##### 使い方

特定のバージョンのインストール

```sh
pyenv install 3.10.1
```

インストール済み&使用中のバージョンの確認

```sh
pyenv versions
```

特定のバージョンを使用するように設定

```sh
pyenv global 3.10.1
```

特定のプロジェクト内で使用するバージョンを設定

```sh
pyenv local 3.10.1
```


より詳しい使い方は[公式GitHub](https://github.com/pyenv/pyenv#usage)をご覧ください。


### パッケージ管理・仮想環境管理

各種ライブラリのインストールおよびアップグレード、そしてライブラリ間の依存関係などを整理してくれるのがパッケージ管理ソフトです。
プロジェクトごとに、使用するライブラリセットを備える仮想環境管理も開発に重要な要素の一つです。専用のソフトもありますが、近年ではパッケージ管理ソフトに機能として備わっているケースも多いです。

#### Poetry

https://cocoatomo.github.io/poetry-ja/

Pythonのパッケージ管理ソフトとしては、Python3.4以降に標準付属している**pip**、 比較的新しく、仮想環境構築もできる**pipenv**などがありますが、新しく、より良いものを選ぶならば、**Poetry**に軍配があがるでしょう。

:::note warn
PoetryはPython3.5以上でサポートされています。(Poetry 1.1系)
また今後、Python3.5もサポート対象から外れる予定ですので、使用する際には注意しましょう。
:::

pip時代は、`requirements.txt`に使用ライブラリが一覧管理されているのみだったPythonプロジェクトですが、Poetryを使えば、依存関係もしっかり解決してくれます。
Poetryでは、`pyproject.toml`というtoml形式のファイルに、使用ライブラリとその依存関係が整理されます。

##### インストール

Poetryのインストール手順は下記公式ドキュメントをご覧ください。

https://cocoatomo.github.io/poetry-ja/

macでHomebrewを利用しているならば、以下でもインストール可能です。（公式非推奨）

```sh
brew install poetry
```

以下のコマンドで、`Poetry (version 1.1.0)`といったバージョン情報が表示されればインストール成功です。

```sh
poetry -V
```

##### Pythonプロジェクト作成

poetryコマンドで、Pythonプロジェクトの作成ができます。

```sh
poetry new poetry-demo
```

成功すると、以下のようなファイル・ディレクトリ群が生成されます。

```
poetry-demo
├── README.md
├── poetry_demo
│   └── __init__.py
├── pyproject.toml
└── tests
    └── __init__.py

```

pyproject.tomlが、パッケージの依存関係を整理してくれます。初期状態では、中身は以下のようになっています。

```toml:pyproject.toml
[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
readme = "README.md"
packages = [{include = "poetry_demo"}]

[tool.poetry.dependencies]
python = "^3.11"


[build-system]
requires = ["poetry-core"]
```

##### 仮想環境起動＆ライブラリインストール

以下のコマンドで、仮想環境の起動が行えます。
```sh
poetry shell
```

実行すると、コマンドプロンプトの左に、起動している仮想環境が表示されます。

```bash
(poetry-demo-py3.11) user@hogehoge:~/poetry-demo $
```

試しにscikit-learnというライブラリをインストールしてみましょう。

```sh
poetry add scikit-learn
```

実行結果の下部に、以下のような項目が表示されます。

```
Package operations: 5 installs, 0 updates, 0 removals

  • Installing numpy (1.24.0)
  • Installing joblib (1.2.0)
  • Installing scipy (1.9.3)
  • Installing threadpoolctl (3.1.0)
  • Installing scikit-learn (1.2.0)
```

scikit-learnをインストールする際に、numpyなどの別のライブラリもインストールされたことがわかります。
pyproject.tomlは以下のように変化しました。

```toml:pyproject.toml
[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
readme = "README.md"
packages = [{include = "poetry_demo"}]

[tool.poetry.dependencies]
python = "^3.11"
scikit-learn = "^1.2.0"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
```

`[tool.poetry.dependencies]`に、scikit-learnが追加されていますね。プロジェクトの依存ライブラリは、このように追加されていきます。




### Linter

Linterは、コードの静的解析を行い、問題点が無いかをチェックしてくれるツールです。
PythonのLinterとしては、**pylint**、**flake8**などが有名です。
コードの保守性・安全性を保つためにマストなので、必ず使用することをおすすめします。

#### flake8

https://flake8.pycqa.org/en/latest/#

現在より多く使われているのはflake8になると思います。
flake8は下記の3つのライブラリがまとまったラッパーライブラリで、文法・コーディング規約・複雑さをまとめてチェックしてれるのが強みです。

- PyFlakes
    - Pythonの文法に準拠しているかをチェックします。
- pycodestyle
    - 元々はpep8というライブラリでした。
    - [PEP8](https://peps.python.org/pep-0008/)というPythonコーディング規約に準拠しているかをチェックします。
- Ned Batchelder’s McCabe script（McCabe)
    -  Pythonコードの複雑さ([循環的複雑度](https://ja.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E7%9A%84%E8%A4%87%E9%9B%91%E5%BA%A6))をチェックします。



##### インストール

[公式ドキュメント](https://flake8.pycqa.org/en/latest/#)では、pipを使ったインストール方法しか紹介されていません。

Poetryを使ったインストール方法は以下の通りです。（`-D`はdevモード、開発時にのみ必要なライブラリをインストールする際のオプションです。）

```sh
poetry add flake8 -D
```

インストール完了後、`flake8 --version`を実行すると、以下の様な結果か表示されるはずです。

```sh
6.0.0 (mccabe: 0.7.0, pycodestyle: 2.10.0, pyflakes: 3.0.1) CPython 3.11.0 on Darwin
```

上述した3ライブラリ（mmcabe, pycodestyle, pyflakes）がそれぞれ内包されていることがわかりますね。


##### 使い方

解析したいプロジェクトディレクトリで、以下のコマンドを実行するだけです。

```sh
flake8
```

また、解析対象を特定のファイルに限定することもできます。

```sh
flake8 main.py
```

### Formatter

Linterがコードの問題点を解析してくれるのに対して、コードのスタイルをチェックし、自動修正してくれるのがFormatterです。
Pythonのコードスタイルについては、コード規約であるPEP8に従うのがまず第一なのですが、規約ではカバーしていない部分について、ルールを定めて自動修正してくれます。

例えばシングルクォーテーションとダブルクォーテーションの使い分け、改行の位置など、個人差が生じるような部分については、Formatterでカッチリと定めてしまうほうが、誰にとっても読みやすいコードになります。

#### Black

https://black.readthedocs.io/en/stable/index.html

他にも[**issort**](https://pycqa.github.io/isort/)などのライブラリが存在しますが、現在最もデファクトスタンダードに近いのは**Black**だと言えるでしょう。

Blackの大きな特徴は、個別設定によるバリエーションを許さない厳格さにあります。
「厳格」というと窮屈に感じるかもしれませんが、フォーマットが厳格に固定されることで、「どう書くか」を気にしたり、議論したりする一切の手間が省ける、ということでもあります。
その分、よりクリーンなコードの書き方や、より重要なドメイン知識の考察などに割ける時間が増えるのは、エンジニアにとって大きなメリットになります。

##### インストール

こちらも[公式サイト](https://black.readthedocs.io/en/stable/getting_started.html)にはpipでのインストール方法しか書かれていませんが、Poetryでもインストール可能です。


```sh
poetry add black -D
```

##### 使い方

flake8と同じく、コマンド一発で使用できます。

```sh
black (ファイル or ディレクトリ)
```

[公式ドキュメント](https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html)で、より発展的な使い方も確認できます。


#### isort

https://pycqa.github.io/isort/

Blackと併用されるパターンが増えて来ているようです。[公式](https://pycqa.github.io/isort/docs/configuration/black_compatibility.html)でも、Blackとの併用・互換性について説明されています。

import文をPEP8準拠にソートしてくれるFormatterです。複数のモジュールをimportすると、import文の順番がぐちゃぐちゃになりやすいので、これを使って修正することで可読性を上げていきたいところです。

### 単体テスト

単体テスト(ユニットテスト)は、プログラムの最小構成単位(例えば関数)が正しく動作することを確認するために行うテストです。
機能の実装にばかり追われてテストを書かないままにしていると、いつの間にかプログラム全体の動作の担保が難しく、かつ修正も困難な状況に追い込まれていきます。

単体テストツールは、プロジェクト作成段階から導入すべきです。後回しにして良い理由はありません。

#### pytest

https://docs.pytest.org/en/7.2.x/

Pythonには標準ライブラリとして**unittest**がありますが、現在のデファクトスタンダードといえば**pytest**になると思います。
unittestの欠点をカバーする目的で開発されたライブラリで、毎回テストクラスを定義しなければならないunittestと違い、関数単位でシンプルにテストを追加できる点などが魅力です。またunittest用に書かれたテストも実行できるため、unittestからの移行も簡単にできます。

拡張機能も豊富で、テストカバレッジを計算してくれる**pytest-cov**などは特に便利です。

https://pypi.org/project/pytest-cov/


##### インストール

例によってpipでインストールする場合は[公式ドキュメント](https://docs.pytest.org/en/7.2.x/getting-started.html)を参照してください。

Poetryを使う場合は以下です。

```sh
poetry add pytest -D
```

##### 使い方

下記のコマンドで、実装したテスト関数をテストしてくれます。

```sh
poetry run pytest
```

テスト関数の書き方などは、ドキュメントに詳しく書いていますが、

- ファイル名のprefixを、 `test_***.py` 
- 関数名のprefixを、 `test__×××`


として定義すれば、pytestのテスト対象となります。

### 型定義・解析

Pythonは動的型付け言語なので、型を定義する必要がありません。
が、3.5系以降は型ヒントを付けることが可能になり、現在は多くのプロジェクトで、保守性・可読性の観点から用いられています。

エディタの拡張機能なども含め、型の導入・静的解析ができる環境を用意することは、モダンなPythonプロジェクトでは、ほぼ必須条件と言えるでしょう。


#### typing

https://docs.python.org/ja/3/library/typing.html

Pythonの標準ライブラリの一つで、柔軟な型表現を導入し、型ヒントを助けてくれるツールです。
3.5系以降のPythonならば、importするだけで使えます。


```py
from typing import List

def hoge() -> List[int]:
    return [0, 1, 2]
    

print(hoge())
```

こんな形で`hoge`関数の返り値として`int`の`list`を指定できるなど、typingを導入することで付けられる型ヒントのバリエーションはグッと広がります。

型エイリアス（型を命名して使う）などの便利な機能もありますので、より詳しい使い方は公式ドキュメントをご覧ください。

#### mypy

https://mypy.readthedocs.io/en/stable/index.html

Python型チェックライブラリの先駆け的存在であり、かつデファクトスタンダードと呼べるライブラリです。
若干重いのが欠点ですが、他に依存する要素もなく、シンプルかつ十分な機能を有しています。


##### インストール

Poetryを使ったインストールは下記のとおりです。

```sh
poetry add mypy -D
```

##### 使い方

`poetry run`のサブコマンドとして実行します。

```sh
poetry run mypy (ファイル or ディレクトリ)
```

### テスト・解析管理

#### Nox

https://nox.thea.codes/en/stable/

Noxは複数のテストや解析ツールを管理してくれるツールで、[tox](https://tox.wiki/en/latest/)の後継にあたります。
これまで紹介してきた各種ツールを、独立した環境で自由に動かすことができます。
Noxの特徴としては、設定ファイルをPythonスクリプトとして書ける点です。`noxfile.py`というファイルを作成し、実行したいテストを追加していきます。


##### インストール

```sh
poetry add nox -D
```

##### 使い方

`noxfile.py`は以下のように記載してきます。

```py:noxfile.py
import nox
import nox


@nox.session
def tests(session):
    session.install('pytest')
    session.run('pytest')


@nox.session
def lint(session):
    session.install('flake8')
    session.run('flake8')

```

実行はコマンドを叩くだけです。

```py
nox
```

### テスト自動化

CircleCIやGithub ActionsなどのCI/CDサービスは多くのプロジェクトで利用されていますが、コミット前に全てのテストを通しておけば、いたずらにパイプラインを落とすこともなく、他のメンバーに影響を与えることもありません。

Gitには、コミット前に任意のアクションを自動実行してくれる`pre-commit`フックがあります。

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF

が、この設定は`.git/hooks`以下に記載するため、チーム開発などでは設定を簡単に共有できないのがネックです。これを解決するために、**pre-commit**という（名前そのまんまな）多言語パッケージマネージャが開発されています。

#### pre-commit

https://pre-commit.com/

pre-commitは、全てのコミットの前にあらゆるフックのインストールと実行を行ってくれる管理ツールです。
フックして登録したいテストや解析は、`.pre-commit-config.yaml`というファイルでステップ別に記述・管理します。`.pre-commit-config.yaml`自体ももちろんコミットすることができるので、コミット前に自動実行したいあらゆる手順をチーム内で共通化することができます。

##### インストール

```sh
poetry add pre-commit -D
```

##### 使い方

例えばコミット前にflake8を実行したい場合は、以下のような形で`pre-commit-config.yaml`を記述します。

```yaml:.pre-commit-config.yaml
repos:
-   repo: local
    hooks:
    -   id: flake8
        name: flake8
        entry: poetry run flake8
        language: system
        types: [python]
```

yamlファイルの設定は、以下のコマンドで`.git/hooks`以下に反映させます。

```sh
pre-commit install
```

これで、設定したフックがコミット前に走るのですが、`pre-commit run --all-files`を叩いて手動実行も可能です。
より詳しい使い方は、[公式ドキュメント](https://pre-commit.com/#usage)をご覧ください。

# おわりに

本記事では、最新のPythonプロジェクトで用いられるツールについて、用途ごとに解説してきました。
Pythonコミュニティでは、ここで紹介した以外にも多くの優れたツールが群雄割拠しており、「デファクトスタンダードはこれ」を一概には言い切れないケースも多いのですが、この記事で触れているものについては、まず入れておいて損はないツール群をまとめたつもりです。

もし「もっと良いツールがある」「一番使いやすいLinterはこれだ」といったご意見がございましたら、コメントで教えていただけると嬉しいです。

---

弊社では、経験の有無を問わず、社員やインターン生の採用を行っています。

興味のある方は[こちら](https://www.recruit.nuco.co.jp/?qiita_item_id=733d67ff39acb41839f2)をご覧ください。