Pythonライブラリを自作してみた

## 概要

ということで、Pythonライブラリ自作してみたので、その方法について書いてみました。
……とはいっても、先駆者様が立派な記事を書いていらっしゃるので、基本的に私がつまづいた部分や、オリジナルな部分をメインに書いていこうと思います。
この記事を見れば、

- 自作ライブラリが作れる
- ディレクトリ構成の参考になる

と思うので、ぜひ見ていってください。

## 環境

たぶん関係ないと思いますが、念のためのっけておきます。

- Windows10
- Python3.8

## 私のディレクトリ構成

まずは、私のディレクトリ構成を見てもらいたいと思います。
この記事を読んでいけば、この構成の意味がなんとなく分かるようになると思います。

```
.
├── .gitignore
├── MANIFEST.in
├── README.md
├── package
│   ├── __init__.py
│   └── func.py
├── notebook
│   └── test.ipynb
├── requirements.txt
└── setup.py
```

……とは言いましたが、実はほとんどがこちらの記事を見ればわかるような内容になっています。

[あとで後悔しないPythonのディレクトリ構成をつくってみる](https://qiita.com/kobori_akira/items/aa42790354654debb655)

ということで、この記事に載っていて私が実装しなかったもの、追加したもの、補足等をしていきたいと思います。
あと、実際にこのディレクトリ構成でGithubにあげてみているので、もしよろしければこちらもご覧ください。

https://github.com/kotabrog/image_100

## 実装しなかったもの

### コマンドラインでの実行機能

私が作りたかったものはコマンドラインでの実行が不要だったので、削りました。
削ったものは以下になります。

- cli.py
- setup.pyの以下の部分
 
```python:setup.py
entry_points = ...
```

### pytest

これはいいなとも思いつつ、今は特別に必要ないかなと思い削りました。
削ったものは以下になります。

- tests/

### requirementsのバージョン

これは場合によると思うのですが、バージョン関係なくだいたい動くかな？という時には、バージョン情報まで書かなくてもいいかなと思って削りました。
こうすれば、詳しくはわかりませんが、例えばちょっと古いバージョンで実装しなければいけないときに、自作のライブラリのせいで新しいバージョンにされてしまった……ということが防げるかなぁと思いました。
ですので、私のrequirements.txtは例えばこんな感じになっています。

```
matplotlib
numpy
scikit-image
```

## 追加したもの

### Notebook

これはライブラリのためというよりは、こんな感じで実行するよーみたいなのを載せたり、テスト過程を載せたりするものです。
ライブラリには不要ですし、ファイルサイズが大きくなってしまうので、readmeに消してもよい旨なんか書いたほうが親切かもなぁなんて思っています。

また、そのため.gitignoreに以下を追加しています。

```
.ipynb_checkpoints/
```

これ必要なのかな？とも思ったのですが、何かと邪魔をすることがあるので、gitにはあげないほうが良いみたいです。

[jupyterのcheckpoints関連ファイルをgit管理から外す](https://qiita.com/analytics-hiro/items/c243e8dd61b4461e76d7)

## 補足（というか私がつまづいたこと）

もちろん参考にした記事はとてもわかりやすかったのですが、私の知識不足のためいろいろ調べまわったことを書いていきます。
一人がつまずいたら１００人はつまづく法則があるので（ない）、きっと誰かの役に立つ。

### フォルダ構成について

自作ライブラリ以外にも、一般的なフォルダ構成の仕方ってどうやるんだろう？という状況だったので、いろいろと参考にさせていただきました。

[プロジェクト構成](https://rinatz.github.io/python-book/ch04-06-project-structures/)
[プロジェクトの構造化](https://python-guideja.readthedocs.io/ja/latest/writing/structure.html)
[データ分析をするときのフォルダ構成](https://www.st-hakky-blog.com/entry/2017/03/24/140738)

### importってどうやるんだっけ……？

自分で作った関数とかを別ファイルから読み込むときの方法について迷ったのでまとめておきます。

[pythonで自作関数をモジュール化・パッケージ化](https://qiita.com/ren094275/items/5d42f7c6be8c5d3cd014)
[Pythonの相対インポートで上位ディレクトリ・サブディレクトリを指定](https://note.nkmk.me/python-relative-import/)
[Python, importの使い方（from, as, PEP8の推奨スタイル, 注意点など）](https://note.nkmk.me/python-import-usage/)

### \_\_init\_\_ってなんだ！

なんとなくでしか知らなかったのでいろいろ調べてみました。

- とりあえずこれを見ればわかる->[Python の \_\_init\_\_.py とは何なのか](https://qiita.com/msi/items/d91ea3900373ff8b09d7)
- モジュール名のカットができる->[Python \_\_init\_\_.pyの書き方](https://qiita.com/FN_Programming/items/2dcabc93365a62397afe)

また、\_\_all\_\_というのが設定されると、

```python
from package import *
```

みたいなことができるようになるのですが、\_\_all\_\_を自分で書くのはめんどくさい……というときに\_\_init\_\_に書くコードがありました。

- \_\_all\_\_について-> [Pythonの特殊変数\_\_all\_\_について現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/41656)
- つっこむ方法-> [\_\_init\_\_.pyと同じ階層にあるpythonファイルを全部\_\_all\_\_に突っ込む](https://medium.com/@hokan_dev/init-py%E3%81%A8%E5%90%8C%E3%81%98%E9%9A%8E%E5%B1%A4%E3%81%AB%E3%81%82%E3%82%8Bpython%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%85%A8%E9%83%A8-all-%E3%81%AB%E7%AA%81%E3%81%A3%E8%BE%BC%E3%82%80-ac632f71594)

ただこの方法、実は環境によって動かないことがあります。
その理由は、windowsとmacでディレクトリのつなぎ方が違うせいなんです……（なぜ統一できなかったのか……）
ということで、以下を参考に書き換えたものをはっておきます。

[Pythonで文字列を分割（区切り文字、改行、正規表現、文字数）](https://note.nkmk.me/python-split-rsplit-splitlines-re/)

```python:__init__.py
import glob
import os

py_list = glob.glob('package/*.py')
__all__ = list(map(lambda file_path: os.path.basename(file_path).split('.', 1)[0], py_list))
__all__.remove('__init__')
```

ちなみに、これだと全部呼び出せるようになってしまうので、呼び出せるものを選びたいときには、やっぱり手動で書いたり、呼び出したくないものをファイルにまとめておいてそれをallから削除する……というやりかたがいいのかもしれません。

### その他

[\_\_pycache\_\_って何？](https://qiita.com/Kobayashi2019/items/03e31ee50b924f428e71)

## 終わりに

ということで、先駆者様より良い記事を書ける自信がなかったので、まとめみたいな感じにさせていただきました。
もし「ここが違うよ！」というところがあったら、教えていただけたら嬉しいです。