コールバック関数を使って異なる関数をリストにとった一括処理を可能にする

#はじめに
このポストでは、いくつかの外部モジュールから複数の関数を取り出し、それぞれのモジュール関数を同一ループ処理することを目指します。

#使い方
・同一のデータセットに対し、異なる算術関数を適用し比較したい場合
・複数サイトのクローリングなど、アクセス先は違うが内部処理は同じ場合など

#参考url
[コールバック関数とは](https://qiita.com/pocket8137/items/df5afba90b51e90587a5)
[Pythonにてコールバック関数を使う](https://qiita.com/moroku0519/items/315cd25d3eaae3217103)

##コールバック関数とは
>[コールバック関数とは](https://qiita.com/pocket8137/items/df5afba90b51e90587a5)
>>コールバック関数とは他の関数に引数として渡す関数のこと。
基本は、
1. ハンドラーを定義
2. コールバック関数を定義
3. 関数ポインタにコールバック関数を代入
4. 関数ポインタをハンドラーの引数として渡す

#コールバック関数の使い方

まずhandlerという,関数を呼び出すための関数を定義します。

```.py
def handler(func,*args):
    return func(*args)
```
次に引数として使いたい関数を定義します。

```.py
def double(x):
    return x*x
```
最後にhandlerを使って上の関数を呼び出します。

```.py
k = 5
call = handler(double,k)
print(call)

>>>25
```
主な使い方としては、変数をlambda式で書ききれない場合にコールバック関数を使用する感じでしょうか。

#本題
さて、コールバック関数の使い方は分かりました。これを使って複数の関数を処理してみましょう。

まず、いくつかの関数が定義された外部モジュールhoge.pyを定義します。

```hoge.py
def add(x):
    return x+1

def sub(x):
    return x-1

def mul(x):
    return x*1

def div(x):
    return x/1

```
次に、このhoge.pyをメインモジュールにインポートし、関数のリストとして定義します。

```main.py
import hoge
func = [hoge.add, hoge.sub, hoge.mul, hoge.div]

```
pythonはすべてがオブジェクトと言う通り、関数も配列として格納できます。
もちろん、このまま使うこともできます。

```.py
func[0](1)
>>>2
func[1](1)
>>>0
```
それでは、メイン関数を定義していきましょう。
関数を呼び出すhandler関数と、それを使ったmath関数を定義します。

```main.py
import hoge
func = [hoge.add, hoge.sub, hoge.mul, hoge.div]

#ハンドラーの定義
def handler(function, *arguments):
    return function(*arguments)

#四則演算関数mathの定義
def math(lists):
    def add(x):
        return handler(lists[0], x)

    def sub(x):
        return handler(lists[1], x)

    def mul(x):
        return handler(lists[2], x)

    def div(x):
        return handler(lists[3], x)
    
    return add, sub, mul, div

def main(x):
    #関数の定義
    add,sub,mul,div = math(func)
    
    #それぞれの関数の和
    sum = add(x)+sub(x)+mul(x)+div(x)
    return sum
```

handler関数は任意の関数を引数にとり、その戻り値を返す関数でした。
math関数はfuncリストから関数を受け取り、新しい関数名として出力する関数です。
つまり、

```.py
add, sub, mul, div = math(func)
```
とした時、

```.py
add(x) == hoge.add(x)
sub(x) == hoge.sub(x)
mul(x) == hoge.mul(x)
div(x) == hoge.div(x)
```
という関係が成り立ちます。
main関数ではそれらの関数にxを代入したときの和を計算しています。

#本題の本題
こんなことをしてなんの意味があるのでしょうか？
ここで、新たな外部モジュールfuga.pyを定義します。

```fuga.py
def add(x):
    return x+2

def sub(x):
    return x-2

def mul(x):
    return x*2

def div(x):
    return x/2
```
hoge.pyとfuga.pyはよく似ていますが、それぞれ違う関数です。これをメインモジュールにインポートします。

```main.py
import hoge
import fuga

#辞書型に変更
funcs = {'hoge':[hoge.add, hoge.sub, hoge.mul, hoge.div],
         'fuga':[fuga.add, fuga.sub, fuga.mul, fuga.div],
        }


#ハンドラーの定義
def handler(function, *arguments):
    return function(*arguments)

#四則演算関数mathの定義
def math(lists):
    def add(x):
        return handler(lists[0], x)

    def sub(x):
        return handler(lists[1], x)

    def mul(x):
        return handler(lists[2], x)

    def div(x):
        return handler(lists[3], x)
    
    return add, sub, mul, div

#辞書のリストごとに関数を実行する
def main(x):
    calc_list = []
  
    for lists in funcs.values():
        add,sub,mul,div = math(lists)

        sum = add(x)+sub(x)+mul(x)+div(x)
        calc_list.append(sum)

    return calc_list
```
わかりやすいようにfuncsという辞書型リストを作成しました。これによって、外部モジュールそれぞれの関数がfuncsに格納されました。
また、main関数を一部変更し、外部モジュールそれぞれの関数リストからmath関数を呼び出せるようにfor文で囲み、ループ処理の結果を配列として出力するようにしました。

以上のような書き方をすることで、hoge.pyとfuga.pyからそれぞれ異なる関数を読み込み、main関数内で同一ループ処理することが可能になりました！

#実行結果
実行結果は以下になります！

```main.py
for i in range(10):
    print(main(i))

>>>'''
[0.0, 0.0]
[4.0, 4.5]
[8.0, 9.0]
[12.0, 13.5]
[16.0, 18.0]
[20.0, 22.5]
[24.0, 27.0]
[28.0, 31.5]
[32.0, 36.0]
[36.0, 40.5]

'''
```
2つの外部関数の結果を一度で比較することができました！


#おわりに
新たに外部関数を定義したら辞書にポンポン追加していくだけでmain関数を拡張できるのがこの手法のいいところだと思います。
コールバック関数の勉強にもなりました。
ここまで読んで頂きありがとうございました。