Pythonを選ぶ上で注意しておくべきこと

# Pythonを選ぶ上で注意しておくべきこと
プロジェクトを立ち上げようといったときにプログラミング言語はどうするか？ということも決めなくてはなりません。そこで本投稿ではPythonを選ぶ上で注意しておくべきこととして、実例をもとにまとめました。参考になればと思います。
## 誰のための記事か
本投稿は以下の人に向けた記事です。

- 他のプログラミング言語を使いこなしていてPythonの雰囲気はわかる人
- Pythonのチュートリアルっぽいことはやったけど現場では書いていない人
- Pythonに興味があるプログラミング初心者

## 目次
- Pythonは良い言語
    - ファイルにベタ書きして良い時とそうでない時がある
    - 型宣言しなくて良い訳ではない
    - 思ったより簡単に書ける言語ではない
    - 可読性は低くなりがち
- それでもPythonを選ぶ理由

## Pythonは良い言語
Pythonはシンプルで良いですよね。とても気に入っています。型宣言しなくていいし、JavaScriptみたいな非同期処理じゃないし沢山ライブラリが公開されてるし、トラブルが起きてもネットに解決法がごまんとあります。しかしながら**これらを理由にPythonを選ぶと痛い目に遭います。**以下にその例を紹介します。

## ファイルにベタ書きして良い時とそうでない時がある

### 単一のファイルで動作する(という偏見)
Pythonはスクリプト型言語という位置付けなので、複数のファイルに分けてコンパイルしてビルドするといった認識は薄く、どうしても単一のファイルで動作するようなイメージが強いです。
例えばC/C++なら

```cpp:common.h
#include <stdio.h>

void fuga(unsigned char* piyo);
```


```cpp:common.cpp
#include “common.h”

void fuga(unsigned char* piyo)
{
   piyo += piyo;
}
```


```cpp:main.cpp
#include”common.h”

extern void fuga(unsigned char* piyo);

int main()
{
    unsigned char nyan = 0;
    fuga(&nyan);
    return 0;
}
```

```shell
>cl /c main.cpp common.cpp
>link main.obj common.obj /OUT nyan.exe
```
といったように関数や機能単位でファイルを作り、コンパイルｰ>リンクｰ>実行ファイルの生成という流れですが、Pythonの場合はそのシンプルさから

```python:nyan.py

def fuga(piyo):
    piyo += piyo
    return piyo

nyan = 0

nyan = fuga(nyan)
```

```shell
python nyan.py
```

というように単一のファイルを実行します。

### 神ファイル

Pythonはコンパイル・リンクといったことを考えずに書いたプログラムを実行することができるので、一つのファイルに全ての機能が盛り込まれた**神ファイル**を作ってしまいがちです。というか作りたくなります。するとどうなるかというとコーディングとは別の問題が生じます。コーディングは複数人で行うことが多く、分担します。同一ファイルを複数人で操作すると**差分が競合する**など混乱を招きます。

### 前提を意識しよう

自分しか使わない場合はファイルにベタ書きでも構いませんが、Githubに公開するときや複数人で操作することが前提になる場合は**機能ごとにファイルを分けて**、mainにあたるファイルで他のPythonファイルやその中にある特定の関数をimportするようにしましょう。

## 型宣言しなくて良い訳ではない

### 実行時のエラーが大半
Pythonと言えば動的型付け。int, System.IO,...といった型名やとりあえずvarで宣言する必要はありません。だからといって型を意識しなくて良いかということはなく、Pythonで**主に起きるエラーは型によるもの**だと言っても過言ではないでしょう。例えば以下のような場合です。

```python

# 辞書型の変数を宣言
dic = {'a':[0, 1], 'b':[2, 3]}
# 要素を追加
dic['c'] = 4

# 辞書型の変数から値のリストを取得しそれぞれ2倍する
for value in dic.values():
    # キー'c'でエラー発生
    value.append(len(value))
```

キー'c'の要素は数値型ですがPythonの辞書型の各値やリスト型はすべての要素が同じ型である必要はありません。したがって、関数の実行後に辞書型の要素が書き換わっていてもエラーは起きず、その型の組み込み関数等を**実行したとき**にエラーが起きます。実行時のエラーなのでパッと見分かりません。**型についてはむしろ気を遣って**コーディングやデバッグをするようにしましょう。

### 型注釈
そういった経緯がありtypingという機能がPython3.5以降に追加されています。
これは関数の引数や返却値に型の情報(注釈)を付加することができる機能です。詳しくは[typing 型ヒントのサポート](https://docs.python.org/ja/3/library/typing.html)を参照してください。
残念ながらWebにはPython2系の記事も沢山残っていますし、型注釈のついた記事はほとんどないのが実情です。しかし、型チェックを行ったことで増分実行を1分から数秒に削減した[Dropboxの実例](https://navi.dropbox.jp/our-journey-to-type-checking-4-million-lines-of-python)を考えるとプロジェクト進行において**型注釈をつけない理由はありません。**
この記事を目にしたら**今後は必ず型注釈をつける**ようにしましょう。

## 思ったより簡単に書ける言語ではない

### 記法と使い方は違う
Pythonは記法についてシンプルと言えます。ただしコーディングという観点では必ずしもシンプルとは言えません。時にはimportしない純粋なPythonを書くことも必要ですが以下の例を見てみましょう

```python

# 正規表現を扱う上で使うライブラリ
import re

# 機械学習で使うライブラリ
from keras.models import Sequential
from keras.layers import Dense, Activation

# 形態素解析で使うライブラリ
from janome.tokenizer import Tokenizer
# 数値計算で使うライブラリ
import numpy as np
# 画面描画で使うライブラリ
import matplotlib.pyplot as plt

```
**re?Sequential?Tokenizer?なんですかこれは??????**
急に出てきて困惑しますよね。そうです。まずはimportしたクラスについて深く理解する必要があります。本来ならば実装方法まで理解した方が良いとは思いますが、最低限**クラスの役割と振る舞いを理解しましょう。**特に大きなライブラリになるとクラスの中のクラスの中の…といった具合に入れ子になっている場合や、関数に多くの引数が入るケースがあります。こういった観点では他の言語と大きな差がありません。**記法はシンプルで使い方はシンプルではない**ということを留意しておく必要があります。

## 可読性は低くなりがち

### ブロックと呼べる場所が少ない
他の言語では関数を定義するときなど、サマリーを書くことがしばしばあります。Pythonにもそういったサマリーのフォーマットがあります。
[Pythonのdocstringの書き方](https://qiita.com/kanatatsu64/items/d3ef79be0ae0409c8681)
ただし、記法がシンプルなので**ブロックと呼ばれる部分を作りにくい**ことや、関数で**複数の変数を返却できる**ことから、どこでまとめるかをじっくり考える必要が出てきます。switch-case文もありません。例えばfor文も以下のようにリスト内包表記で書ける場合があります。ゆえに、可読性は低くなりがちなのです。

```python
# リスト内包表記
data = [(item**2 + item) for item in items if item % 2 == 0]

# 上記と同じ
data = []
for item in items:
    if item % 2 == 0:
        data.append((item**2 + item))
```

## それでもPythonを選ぶ理由
ここまでPython選ぶ上で注意しておくべき点を挙げましたが、注意深くコードを書けば非常に満足のいくものに仕上がります。ライブラリも豊富にあり、世界中の人たちにとって一番モノを作りやすい言語であることは間違いありません。大事なのは何を目的とするかです。Pythonで書くこと自体が楽だからPythonを選ぶのではなく**楽にモノを作るためにPythonを選ぶ**ことを常に意識しておきましょう。