ディレクトリ・モジュール操作について(pathlib, os, sys)

# この記事で紹介するライブラリ

- pathlib
- os
- sys

# この記事で紹介するライブラリの使用方法

## pathlibの使用方法

| クラス/メンバー | 使用方法 | 動き |
| --- | --- | --- |
| Path() | - | 実行場所のパス取得 |
| Path(\_\_file__) | - | 実行ファイルのパスを取得 |
| resolve() | Path(\_\_file__).resolve() | 絶対パスを取得 |
| parent | Path(\_\_file__).resolve().parent | 親ファイルのディレクトリ取得 |
| joinpath() | path.joinpath('./folder/file.py') | パスの連結 |

## osの使用方法

| クラス/メンバー | 使用方法 | 動き |
| --- | --- | --- |
| basename() | os.path.basename(\_\_file__) | 実行ファイル名の取得 |
| abspath() | os.path.abspath(\_\_file__) | 実行ファイル含めた絶対パスの取得 |
| dirname() | os.path.dirname(\_\_file__) | 親ファイルのパスを取得 |
| join() | os.path.join(path, *paths) | パスの結合 |


# pathlibの詳細

Anacondaの同梱ライブラリで実行するパスや実行ファイルのパスを取得するのに
使用します。

## 実行場所の取得

のちに紹介する`__file__`を使用しない場合は実行したパスを取得します。
事前準備として下記のフォルダとファイルを用意してください。

```
・
└── parent_folder
    ├── parent.py
    ├── chiled_folder
    │ └── chiled.py
    └── child_folder2
        └── chiled2.py
```

### 実行場所を取得

まず下記のコードをparent.pyとchild.pyに書いてください。

```py
from pathlib import Path

print('*****')
print(Path().resolve())
print('*****')
```

その後、parent_folderまでディレクトリを移動して下記をそれぞれ実行してみてください。

c```bash
python parent.py
child_folder/child.py
```

どちらもparent_folderまでの絶対パスがとれましたか？
Path()については実行ファイルは関係せず、実行場所までのパスが取れるという点に
注意してください。


### 実行場所からの移動

他のディレクトリを指定する場合は実行パスからの相対パスを指定します。

```parente_folder.parent.py
from pathlib import Path

print('*****')
print(Path('./child_folder').resolve())
print('*****')
```


## 実行ファイルのパス取得

Pathの引数に`__file__`を渡すことによって実行ファイルまでのパス取得が可能になります。
parent.pyとchild.pyを下記に書きかえて同じように実行していきます。

```py
from pathlib import Path

print('*****')
print(Path(__file__).resolve())
print('*****')
```

すると今後はparent.py、child.pyの実行ファイルまでの絶対パスが取得できたと思います。
ファイルの呼び出し場所に依存せずにパスが取得できるので、
ディレクトリ操作をする場合は`__file__`を使用して間違いない実装をしていきます。

## __file__を使用してディレクトリの移動

ディレクトリの親ファイルに移動するためにはメンバーの`parent`
その後、別のファイルパスとつなげたい場合は`joinpath`メソッドを使用します。

```py:child.py
from pathlib import Path

print('*****')
# parent_folderのパス取得
print(Path(__file__).resolve().parent.parent)

# child_folder2のパス取得
print(Path(__file__).resolve().parent.joinpath('./child_folder2'))
print('*****')
```

まだ実装ではないですが、is_dir(), is_file()はそのうち使おうと思っています。


# os.pathの詳細

## os.pathの役割

OSによってパスの指定方法が異なるが、os.pathを使って指定すると、
os.pathがOS毎に最適なパスの指定をしてくれます。
つまり、OSに依存せずパスの指定が可能になるので、基本的にパスの指定はos.pathを使用します。

pathlibの方がシンプルなので、基本はpathlibを使用したいと思いますが
多くの記事にでてくるので基本操作ぐらいは把握しておいた方がよいかなと思っています。

```py
import os
print('***basename***')
print(os.path.basename(__file__))
print('***dirname***')
print(os.path.dirname(__file__))
print('***abspath***')
print(os.path.abspath(__file__))
```

osのいけていないのはメソッドでラップしないといけない点です。
そのせいでコードの後ろから読み解く必用があり、
パッと見たときに直観的にわかりづらいです。
一方、pathlibだとメソッドチェーンで後ろに操作を追加できるので視覚的にも理解しやすいです。

2つ上ディレクトリの別のフォルダを指定したい場合の比較だと下記になります。
```py
import os
os.path.join(os.path.dirname(os.path.dirname(__file__)), './folder_name')


from pathlib import Path
print(Path(__file__).resolve().parent.parent.parent.joinpath(./folder_name))
```

# sys.pathの詳細


## sys.pathの役割
sys.pathはモジュールを検索するパスを示す<span style="font-size: 150%">**文字列のリスト**</span>になっています。
パスには下記が含まれています。

1. スクリプトファイル（.pyファイル）があるディレクトリ
2. 環境変数PYTHONPATHで指定したディレクトリ
3. カレントディレクトリ
4. 標準ライブラリのためのディレクトリ（3つ）
5. pipでインストールしたサードパーティライブラリのためのsite-packagesディレクトリ

つまり、自分で作成したモジュールを使用する場合は、
sys.pathの中にディレクトリを追加する必要があります。

## sys.pathの中を確認

下記を実行して、sys.pathの中を確認できます。
pprintを使用するとリストの要素や辞書のセットごとに改行してくれて
内容が把握しやすいので使用しています。

```py
import pprint
import sys
pprint.pprint(sys.path)
```

## sys.pathにディレクトリを追加

このような感じでpathを追加します。
pathlibで追加したいディレクトリを指定して、
os.path.joinで文字列に変更した内容をsys.pathに追加しています。

```py
import sys
import os
from pathlib import Path
path = os.path.join(Path(__file__).resolve().parent.parent)
sys.path.append(path)
```