Pythonのフレームワークを理解するために必要な知識メモ


# Pythonの本を読んで学んだことをメモしてきます
　Pythonの勉強中です。読んだ本に関しては、以下ブログ記事参照下さい。


https://karaage.hatenadiary.jp/entry/2020/01/04/154338

　内容的には、この記事では、特にPythonで書かれたフレームワーク（具体的にはTensorFlow、PyTorch等のディープラーニングのフレームワーク）を理解するのに必要だった知識を中心にメモしています。

　以下は前提です。

- 当方、永遠の初心者です。優しくして下さい
- Pythonの基礎中の基礎は理解している読者を想定しています
- `print`の次行の`#`行は、出力結果を意味します
- コメント、編集リクエスト歓迎です

　しばらくは、随時追加、修正していく予定です。

# 全体的な話
## Pythonは全てがオブジェクト
　Pythonは全てがオブジェクトらしいです。雰囲気でオブジェクト指向をやっているので、あんまり意味がわかってないです。

　クラスすらオブジェクトらしいですが、それがどういうことなのかも良くわからないです。以下を読んでもよく分からないです。

[Pythonのオブジェクトとクラスのビジュアルガイド – 全てがオブジェクトであるということ](https://postd.cc/pythons-objects-and-classes-a-visual-guide/)

　当面、理解できなくてもプログラムを読み書きはできているのですが、このことを意識しておくと、いつか悟りをひらけそうな気がするので、最初に書いておきます。

## 公式ドキュメント読むの大切です
　当たり前のことのようですが、結構公式ドキュメントを読んでない人多いと思います（すみません、私もあんまり読んでませんでした）。

　いくつかPython本を読んで気づいてたのですが、本も結構間違っていたり、初心者向けに理解しやすくするために、省略している部分があったりするので、ドキュメントを読むのが大切ですね。日本語もあります。

[Python 3.8.1 ドキュメント](https://docs.python.org/ja/3/)

　全部を隅から隅まで読むのは、厳しいと思いますが、コーディングルールを記載していある、PEP8とかは、さらっと目を通しておくと良さそうです。

[PEP 8 -- Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/)

# クラス関係


## 特殊メソッド `__hoge__` に関して
　よく見る`__hoge__`って表現、一体何なの？という人は、以下記事読むと幸せになりそうです。

[Python初心者でも`__hoge__`使いたい！〜特殊属性，特殊メソッドの使い方〜](https://qiita.com/kazetof/items/751be29f208836cf9bf4)

## `__call__`メソッドでインスタンスを関数のように使う
　以下みたいな書き方ができます。

```python
class Function:
    def __call__(self, x):
        return 2*x

f = Function()
print(f(2))
# 4
```

　あれ？これって関数なの？メソッドでは？と思ったら`__call__`を確認すると良いかもしれません。

　ディープラーニングのフレームワークでは、結構使われているイメージです。

## dataclass
データを格納するのに使われる機能です。使いどころなどは、以下記事参照ください。

https://zenn.dev/karaage0703/articles/3508b20ece17d4

# データ構造

## リスト・タプル・辞書・集合（セット）
　Pythonで複数のデータを扱うときに使われるのが以下4つです。

- リスト： `[ ]`
- タプル： `( )`
- 集合(set)： `{ }` or `set()`
- 辞書： `{ }`

　一人で簡単なプログラムを書くときには、大体リストを使えばこと足りてしまいますが、ディープラーニングのフレームワークでは、当然リスト以外のものもよく使われます。具体的には、教師データのラベルとファイルの対応に辞書が使われたりしますね。

　コードを読むときや、自分で使うときは、これらがどう違うのか、理解しておく必要があります。また、この後、説明しますがタプルの実体は実はカッコでなく、カンマなので注意して下さい。

参考：[[Python]リスト、タプル、辞書、集合の違い](https://qiita.com/taro-ari/items/9f54536fe3c623813db1)


## タプルを作るのはカンマ（カッコは省略可能だけどカンマは省略できない）
　要素が1個のタプルは、以下のように書く必要があります。

```python
tuple = (1, )
print(tuple)
# (1,)
```

　それどころか、そもそもタプルは以下のようにカンマだけでOKです。

```python
tuple = 1,
print(tuple)
# (1,)
```

　入門書では、リストは`[]`でタプルは`()`って書いてあるだけのことが多いので、実はタプルを作るのはカンマ（`,`）というのは、地味に衝撃でした。

　また、Pythonは、アンパック代入と呼ばれる、要素を複数の変数に展開して代入する手法があります（以下のコードだと、`a, b = b, a`の箇所）が、実はこれPythonの内部的にはタプルという扱いになります。

```python
a = 1
b = 2
a, b = b, a
print(a,b)
# 2 1
```

　これも、全然意識せず使っていたので、驚きました。

参考：[Pythonで要素が1個のタプルには末尾にカンマが必要](https://note.nkmk.me/python-tuple-single-empty/)


## 内包表記：
　リストに関して、内包表記と呼ばれる以下のような書き方ができます。

```python
test = [i for i in range(5)]
print(test)
# [0, 1, 2, 3, 4]
```

　内包表記は、集合に対しても使用可能です。

```python
test = {i for i in range(5)}
print(test)
# {0, 1, 2, 3, 4}
```

　`if`つかって、条件に合うものだけ取り出したりもできるので、色々使い勝手が良いです。

## イテレータ・ジェネレータ
　仕様だけみると「こんなん何に使うの？」という感じなのですが、ディープラーニングのフレームワークだと、データセット（教師データの集まり）のローダとして大活躍します。TensorFlow（Keras）だとImageDataGenerator、PyTorchだとDataLoaderですね。

　ディープラーニングは、バッチ（小さいデータのかたまり）に分けて学習を進めていくので、まさにこのイテレータの仕組みが大活躍するわけですね。なので、イテレータの仕組みを理解しないままデータローダを使うとよく分からなくなるので、基本を理解するのが良いです。

　Qiita記事だと以下などが分かりやすいと思いました。

[Pythonのイテレータとジェネレータ](https://qiita.com/tomotaka_ito/items/35f3eb108f587022fa09)



# テストに関して
　何か問題あったとき、テストプログラムを活用できると効率的に問題を切り分けられる場合があるので、知っておくと良いかと思います。

[unittest --- ユニットテストフレームワーク オフィシャルドキュメント](https://docs.python.org/ja/3/library/unittest.html)
[Python標準のunittestの使い方メモ](https://qiita.com/aomidro/items/3e3449fde924893f18ca)
[Pythonのunittestでハマったところと、もっと早くに知りたかったこと](https://qiita.com/jesus_isao/items/f93c11248192645eb25d)



# その他
　あんまりフレームワークとは関係ないけど、知っておくとPythonを読み書きするときに便利なTIPS。

## enumerateを使ってループにインデックスを付ける
　ループの回数にインデックスが必要な場合、enumerateを使うと以下のように簡潔に書けます。

```python
test = ['a', 'b', 'c', 'd', 'e']

for i, x in enumerate(test):
    print(i, x)

# 0 a
# 1 b
# 2 c
# 3 d
# 4 e
````

　大したことではないですが、よく使われるので、知っておくとコードを読み書きするとき便利です。

## modfで数値の整数部と小数部を同時取得
　正確な値取得しようとすると、ちょっと面倒臭いので知っておくと便利です。

```python
import math

print(math.modf(1.5))
# (0.5, 1.0)
print(type(math.modf(1.5)))
# <class 'tuple'>
```

参考：[Python, math.modfで数値の整数部と小数部を同時に取得](https://note.nkmk.me/python-math-modf/)


## Pythonでのアスタリスク `*`の意味
　アスタリスクは、CやC++だと、ポインタなので嫌な思い出しかないのですが、Pythonは全然違うので安心（？）です。以下のまとめをみておくと良さそうです（困った時に調べる感じでも良いかとは思いますが）。

[Python3.xのアスタリスク逆引き](https://qiita.com/LouiS0616/items/1bbe0a9bb93054f6c380)

## `@`で行列の積を計算できる
　`@`で行列の積を計算できます。Python3.5, NumPy1.10.0以降でないと使用できないので注意して下さい。

```python
import numpy as np

x = np.array([1, 2])
y = np.array([1],[2])
x @ y
# array([5])
```

`np.matmul(x,y)`でも同じ結果になります。 `np.dot(x,y)`というのもあるのですが、こちらは3次元以上の配列になると、結果が変わってくるようです（2次元だと、matmul,`@`と同じ結果）。

　機械学習系だと、行列の積はよく使われるので、見かけることもあるかと思います。

# まとめ
　Pythonで学んだことを、フレームワークへの理解を深める知識という観点で簡単にまとめました。他のテーマでも忘れないようにメモしていこうかなと考えています。

　更にPythonを深く知りたいという人は、以下の記事も参考にしてみて下さい。また、他にもっと良い本がありましたら、是非コメントやTwitter等で教えて下さい。

https://karaage.hatenadiary.jp/entry/2020/01/04/154338