Pythonで書きたい！　(1) コードのフォーマットチェック

はじめまして。エンジニアのleo1109です。
初投稿なので、最近触っているPythonの話を書こうと思います。

記事で利用したコードは、すべてGitHub上にアップロードされています。

- https://github.com/shonuma/qiitas/tree/master/20170804

## 今回紹介する話
コードのフォーマットチェック。
PyPIはこちら。

- flake8
    - https://pypi.python.org/pypi/flake8
- isort(紹介できず。。）
    - https://pypi.python.org/pypi/isort

## Pythonでコードを書きたい！
今日は、フィボナッチ数を取得するプログラムをPythonで書きたい！ので書いてみます。
フィボナッチ数は、数列の項が、１個前、２個前の項を足した値となっている数列のことです。
※1,2項目は1と定義されています。

数式で表すと、以下のようなものです。

```
n > 0, n is unsigned Int.
n = 1: F(1) = 1
n = 2: F(2) = 1
n > 2: F(n) = F(n-1) + F(n-2)
```

早速書いてみましょう。
前の値を保持する必要があるので、配列を使って実装してみます。

```
# python 3.5.2

def get_fibonacci_by_index(index):
    if index in [1 ,2]:
        return 1
    fibs =  [1, 1]

    for i in range(3, index + 1):
        c = fibs[i - 2] + fibs[i-3]
        fibs.append(c)

    return fibs[-1]
```
できました！

## 動作確認しよう

ちゃんと動いているのか確認してみます。

```
Python 3.5.2 (default, Dec 19 2016, 00:08:16)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import my_math
>>> x=[]
>>> for i in range(1, 11):
...     x.append(my_math.get_fibonacci_by_index(i))
...
>>> x
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
```
ちゃんと動いているようです。

- 参考：https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0

## なんか気になる
しかしこのコード、微妙に気になるところがあります。
例えば、以下のようなところです。うーん気になる。

```
def get_fibonacci_by_index(index):
    if index in [1,2]:
        return 1
    fibs =  [1, 1]  # イコールの後のスペースの数が2つ？
...
        c = fibs[i - 2] + fibs[i-3]  # i-2とi-3が統一されていない
```

Pythonには、PEP8というコーディング規約があります。

- https://pep8-ja.readthedocs.io/ja/latest/

もちろんこれを守って書けば良いというのはありますが、毎回これが守られているかをチェックしながら書くのは大変ですね。
複数人で開発をしていて、一人だけ違う書き方をして、ごたごたするのも非常に非効率です。そこで登場するのが、コードチェックツールのflake8です。
詳細な説明は他記事等に譲りますが、実際に利用してみましょう。

```
$ flake8 my_math_before.py
my_math_before.py:3:1: E302 expected 2 blank lines, found 1
my_math_before.py:4:19: E231 missing whitespace after ','
my_math_before.py:6:11: E222 multiple spaces after operator
```

ぐぬぬ。怒られました。
だいたい以下のようなことを言っています。

- E302 expected 2 blank lines, found 1
    - 2行空きが必要だけど、１行しかなかったから修正してね。
- E231 missing whitespace after ','
    - カンマの後ろにスペースが必要。
- E222 multiple spaces after operator
    - 演算子の後ろにスペースが複数あるよ。


### 修正しよう
行数と理由が書いてあるので、修正は簡単です。

diffはこのようになりました。

```
3d2
< 
7,8c6
< 
<     fibs = [1, 1]
---
>     fibs =  [1, 1]
11c9
<         c = fibs[i-2] + fibs[i-3]
---
>         c = fibs[i - 2] + fibs[i-3]
```

修正後がこちらです。

```
# python 3.5.2


def get_fibonacci_by_index(index):
    if index in [1, 2]:
        return 1

    fibs = [1, 1]

    for i in range(3, index + 1):
        c = fibs[i-2] + fibs[i-3]
        fibs.append(c)

    return fibs[-1]
```

再度flake8してみましょう。
ファイル名を指定すると対象ファイルだけをチェックできます。
指定しないと、実行したディレクトリ以下を再帰的に見てくれるようです。

```
$ flake8 my_math.py
```
何も表示されませんでした！これは便利ですね。
Jenkinsのビルドジョブ等に組み込むことで、ロジックだけではなく、コードの統一性も担保できそうです。

## まとめ
コードチェックをこまめにしておくと、見通しが良くなり、バグが埋め込まれる可能性が低下します。
詳細な紹介を省きましたが、フォーマットだけではなく、エラーも通知してくれます。

```
# a.py
x = 2
x = z + 3
x = 5
 if x == 5:
  y = 5

$ flake8 a.py
a.py:5:1: E999 IndentationError: unexpected indent
a.py:5:2: E111 indentation is not a multiple of four
a.py:5:2: E113 unexpected indentation
a.py:6:3: E111 indentation is not a multiple of four
```

## 次回は
今回書いたフィボナッチ数の関数のテストを、Pythonで書きたい！

## 追記
フィボナッチ数列の定義が誤っていたのを修正しました。リクエストありがとうございます！