pythonでサブルーチンはどう書くの？

# はじめに
pythonでプログラムを作りはじめたとき、サブルーチンは、どう書くのだろうという疑問を持ちました。
過去の話になりますが、BASIC言語ではプログラムを作るとき、何度も使う部分は一つにまとめて、gosub文で呼び出していたので、pythonにもあるだろうと思っていましたが、そのような文はありませんでした。
pythonのプログラムを学んでいくと、def文で関数をつくって、それを呼び出せば、サブルーチンの代わりになることが分かってきました。さらに、別ファイルに関数をまとめて作っておくと、他のプログラムで利用できるようになり、便利に使えるということもわかってきました。
プログラマーには当たり前の話かと思いますが、これからpythonを始める人に少しでも役立てていただけるように、例を挙げて書いておこうと思います。
# def文の例
### (例) 画像読み込み関数の作成
例えば、openCVを使って画像の編集をしたいが、画像ファイルのパスに日本語が入っていてエラーが出るため、つぎのようなプログラムを作ったとします。

```python
import cv2
from PIL import Image
import numpy as np

file=r'C:\Users\heroshi\OneDrive\画像\abc.jpg'
pil_img=Image.open(file)
np_img=np.array(pil_img)
cv_img=cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
```
PIL(pillow)でファイルを読み込み、numpyアレイに変換し、さらにカラー順を変換して、ようやくopenCVで画像を編集できるようになるのですが、画像を読み込むたびに、この3行を書くのは面倒ですし、分かりにくくなります。そこで、def文で関数を１つ用意し、その中に3行を入れておきます。

```python
import cv2
from PIL import Image
import numpy as np

def load_img(file):
    pil_img=Image.open(file)
    np_img=np.array(pil_img)
    cv_img=cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
    return cv_img

file=r'C:\Users\heroshi\OneDrive\画像\abc.jpg'
cv_img=load_img(file) #関数の呼び出し gosub文のようなもの
```
上のプログラムはdef文で「load_img」という名前をつけた関数を定義しています。プログラムは長くなっていますが、BASIC言語のサブルーチンのように「load_img」を何度も使うときに便利になります。
例えば、画像を2つ読み込んで、画像を足しあわせる場合は次のように書けます。
```python
import cv2
from PIL import Image
import numpy as np

def load_img(file):
    pil_img=Image.open(file)
    np_img=np.array(pil_img)
    cv_img=cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
    return cv_img

file_1=r'C:\Users\heroshi\OneDrive\画像\abc.jpg'
file_2=r'C:\Users\heroshi\OneDrive\画像\def.jpg'
cv_img_1=load_img(file_1) #関数の呼び出し gosub文のようなもの
cv_img_2=load_img(file_2)
mix_img= cv2.addWeighted(src1=cv_img_1,alpha=0.5,src2=cv_img_2,beta=0.5,gamma=0)
```

### (例) 画像の表示関数の作成
画像を表示する際、openCVのcv2.imshowを使って描くよりも、matplotlibのplt.showを使ったほうが拡大縮小も簡単に操作できるので、次のようなプログラムを作って描画しています。
```python
import matplotlib.pyplot as plt
plt_mix_img=cv2.cvtColor(mix_img, cv2.COLOR_BGR2RGB) # BGRからRGBへ変換して表示
plt.imshow(plt_mix_img)  
plt.axis('off')  # 軸を非表示にする
plt.show()
```
こちらも表示させるのに何度も同じ文（4行）を書くのが面倒なので、次のようにdef文で関数を定義します。
```python
import matplotlib.pyplot as plt
def draw_img(image):
    plt_mix_img=cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # BGRからRGBへ変換して表示
    plt.imshow(plt_mix_img)  
    plt.axis('off')  # 軸を非表示にする
    plt.show()

draw_img(mix_img) #関数の呼び出し gosub文のようなもの
```

# 関数だけを別ファイルへ
上の例では、ファイルの読み込みと画像の描画の関数を作りました。その関数だけを別のファイルに入れて、ファイル名は、dif_list.pyとします。

```python
import cv2
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

def load_img(file):
    pil_img=Image.open(file)
    np_img=np.array(pil_img)
    cv_img=cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
    return cv_img

def draw_img(image):
    plt_mix_img=cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # BGRからRGBへ変換して表示
    plt.imshow(plt_mix_img)  
    plt.axis('off')  # 軸を非表示にする
    plt.show()
```

次に実行するファイルを作ります。def_listから関数をインポートすることで、実行ファイルの中身は非常にすっきりします。※実行ファイルと関数のファイルは同じフォルダに入れています。

```python
import cv2
from def_list import * #ここでdef_listのファイルから関数をインポートします。*は、すべてという意味です。

file_1=r'C:\Users\heroshi\OneDrive\画像\abc.jpg'
file_2=r'C:\Users\heroshi\OneDrive\画像\def.jpg'
cv_img_1=load_img(file_1)
cv_img_2=load_img(file_2)
mix_img= cv2.addWeighted(src1=cv_img_1,alpha=0.5,src2=cv_img_2,beta=0.5,gamma=0)

draw_img(mix_img)
```

関数にわかりやすい名前をつけることで、使いやすいものになり、別の実行プログラムでも、関数をインポートすることで同様に使えるようになります。

# 関数の修正や追加時の確認
関数の修正や追加した際に、きちんと動くかを確認したい場合があると思います。こんなとき、関数のファイルの最後に、if _ _ name _ _ =="_ _ main _ _"　文を入れておけば、関数ファイルのみで実行して確認できるようになるので、こちらもお勧めです。
```python
import cv2
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

def load_img(file):
    pil_img=Image.open(file)
    np_img=np.array(pil_img)
    cv_img=cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
    return cv_img

def draw_img(image):
    plt_mix_img=cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # BGRからRGBへ変換して表示
    plt.imshow(plt_mix_img)  
    plt.axis('off')  # 軸を非表示にする
    plt.show()

if __name__=="__main__":
    file=r'C:\Users\heroshi\OneDrive\画像\abc.jpg'
    cv_img=load_img(file)
    deaw_img(cv_img)
```

# さいごに
最初はBASIC言語のサブルーチンってpythonでどう書くんだろうと思っていましたが、pythonを学んでいくうちに、def文でできることを知り、関数を別ファイルとして用意しておけば、インポートするだけで、他のプログラムでも使えるようになるということを知りました。プログラミングの進化を感じた次第です。