Pythonの関数を辞書（dict）のValueに格納して、Keyに応じた関数呼出しをする方法


##1. メソッド（関数）を宣言する

```Python3:Python3
def sample_func_1(text : str) -> str:
    add_text = "追加した文字列"
    return (text + add_text)


def sample_func_2(text : str) -> str:
    add_text2 = "追加した文字列バージョン２"
    return (text + add_text2)

```

##2. 辞書型（*dict*）オブジェクトの*Value*に、関数を括弧を付けずに記述する

```Python3:Python3
func_dict = {
	'label_1' : sample_func_1,
	'label_2' : sample_func_2
	}
```

##3. 辞書型オブジェクト[*Key*ラベル名]()で、関数を呼び出して実行する

辞書（*dict*）のvalue値として、格納されているのは、関数（メソッド）オブジェクトそのものです。
そのため、関数（メソッド）を実行するには、辞書（*func_dict*）のvalue値に、引数を受け取る丸括弧（"( )"）を付ける必要があります。

丸括弧（"( )"）を付けないで、辞書（*dict*）のvalue値として格納されている関数（メソッド）「それ自体」を呼び出した場合の結果は、以下になります。

```Python3:Python3
func_dict['label_1']
<function sample_func_1 at 0x100bafb80>
```

上記のコードで辞書から呼出した関数（メソッド）を実行するには、引数を受け取る丸括弧（"( )"）をつける必要があります。

```Python3:Python3
func_dict['label_1']()

```

__なお、*funct_dict*が引数を1つ以上、受け取るメソッドである場合は、引数を与えないで関数呼出しをすると、エラーが出ます。__

定義したメソッド（関数）は、*str*型のオブジェクトを引数を受け取る関数でした。
引数に適当な文字列を渡して、*func_dict*内に格納されているメソッド（関数）を実行してみます。


```Python3:Python3
func_dict['label_1']("vxw")
# 実行結果
'vxw追加した文字列'

```

#####（ 参考 ）

```Python3:Python3
func_dict
# 実行結果
{'label_1': <function sample_func_1 at 0x100bafaf0>, 'label_2': <function get_text_from_ppt at 0x100bafa60>}

func_dict['label_1']
<function sample_func_1 at 0x100bafb80>

type(func_dict['label_1'])
# 実行結果
<class 'function'>

type(func_dict['label_1']())
# 実行結果
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sample_func_1() missing 1 required positional argument: 'text'

type(func_dict['label_1']("giho"))
# 実行結果
<class 'str'>

func_dict['label_1']("giho")
# 実行結果
'giho追加した文字列'

returned_value = func_dict['label_1']("giho")
returned_value
# 実行結果
'giho追加した文字列'
```

###（ 参考にしたWebページ ）

1. [@satoichiさんのQiita記事 「【Python】辞書を利用して関数をまとめて実行する」](https://qiita.com/satoichi/items/8430aa1397d9801ef10d)
2. [「[Python] **を用いたキーワード引数の辞書化」](https://www.yoheim.net/blog.php?q=20160610)

##（ 使いみち ）

今回、紹介した方法を用いることで、辞書型オブジェクトに定義された*Key*の値に応じて、その*Key*に対応する関数（メソッド）を呼び出すことができます。

データを処理する流れのなかで、条件に応じて、呼び出すべき適切な関数（メソッド）が切り替わるロジックが必要な場面で、役に立ちます。

基本的な例として、読み込んだファイルの拡張子の内容に応じて、そのファイルに所要の処理を行う関数（メソッド）を動的に選び出して呼出して実行する場面、などが考えられます。

PDFファイルやWordファイル、Excelファイルから、テキスト文字列のみを切り抜いてデータ取得するコードは、以下のWebページで紹介されています。

1. [deecode blog 「[Python] Word/Excel/PowerPoint/PDFからテキスト抽出するライブラリ・サンプルコード」](https://deecode.net/?p=852)
2. [@butadaさんのQiita記事 「pdf/docxファイルからのテキストマイニング」](https://qiita.com/butada/items/afce4d16cbd93f2bbff9)

また、受け取ったファイルの絶対パスから、パスの末尾に記載されている拡張子をPythonで取得するコードは、以下で取り上げられています。

・ [ファイルの拡張子を取得する](https://www.gesource.jp/programming/python/code/0010.html)


```Python3:Python3
file_abstract_path = 'C:\\foo\\bar\\test.txt'

import os.path
root, ext = os.path.splitext(file_abstract_path)
# 拡張子は、extに格納されている。
print(ext)
# 上の例では、".txt"が出力される。

def get_text_from_txt(filename : str) -> str:
    filenameとして受け取ったパスに格納されているテキストファイルをreadして、テキストを*str*オブジェクトとして取得して、返り値として出力する処理

    return text

def get_text_from_pdf(filename : str) -> str:
    filenameとして受け取ったパスに格納されているPDFファイルをreadして、テキスト文字列を抜き出して、ひとつの*str*オブジェクトに連結して、返り値として出力する処理
    return text

def get_text_from_word(filename : str) -> str:
    filenameとして受け取ったパスに格納されているWordファイルをreadして、テキスト文字列を抜き出して、ひとつの*str*オブジェクトに連結して、返り値として出力する処理
    return text

def get_text_from_excel(filename : str) -> str:
    filenameとして受け取ったパスに格納されているExcelファイルをreadして、テキスト文字列を抜き出して、ひとつの*str*オブジェクトに連結して、返り値として出力する処理
    return text

func_dict = {
	'txt' : get_text_from_txt,
	'pdf' : get_text_from_pdf,
    'word' : get_text_from_word,
    'excel' : get_text_from_excel
         }

```

__（ 事後追記 ）__

以下の記事でやってみました。

・ [「PDF・Word・PowerPoint・Excelファイルからテキスト部分を一括抽出するメソッド」](https://qiita.com/Afo_guard_enthusiast/items/0b7c3631f9db3f2e1104)

##（ 備考 ）

辞書の*Value*に関数（メソッド）を格納するときに、関数に括弧を付けると、以下のエラーが発生する。
関数の実行を行おうとしていると、解釈されてしまうため。

```Python3:PZython3
func_dict = {
	     'label_1' : sample_func_1(),
	     'label_2' : sample_func_2()
		 }
# 実行結果
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: sample_func_1() missing 1 required positional argument: 'text'
 
```

辞書を定義する上のコードのなかで、*sample_func_1()*の括弧のなかに特定の引数を与えると、辞書は定義できる（エラーは起きない）。

しかし、辞書の*Value*に格納された関数は、辞書を定義する際に受け取った引数しか、受け取ることのできない関数になってしまう。

__（ 辞書の定義 ）__

```Python3:Python3
func_dict = {
    'label_1' : sample_func_1("abc"),
    'label_2' : sample_func_2("def")
}

```

__（ 辞書内の関数の呼出し実行 ）__

*func_dict*辞書内で、*Key*"*label_1*"に対応する*Value*として定義されている、関数*sample_func_1("abc")*が、引数"abc"を与えられた状態で、実行された。

```Python3:Python3
func_dict['label_1']
# 実行結果
'abc追加した文字列'
```

*func_dict['label_1']*（を評価すると）は、すでに返り値として、*str*型のインスタンス*'abc追加した文字列'*を返している。そのため、*func_dict['label_1']*にさらに括弧を付けると、*TypeError: 'str' object is not callable*エラーが起きる。

```Python3:Python3
func_dict['label_1']()
# 実行結果
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable

```

```Python3:Python3
func_dict['label_1']("abc")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable

```

```Python3:Python3
unc_dict['label_1']('abc')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable

```

___

##（ 備考２ ）

__辞書の*Val*にテキスト文字列を格納して、*eval*と*exec*を用いて、関数をよびだせる。__

__しかし、キーボードのストローク数が増えてしまい、エレガントではない。__

```Python3:Python3
func_dict = {
    'label_1' : "sample_func_1({arg})",
    'label_2' : "sample_func_2({arg})"
    }
```

```Python3:Python3
func_dict
# 実行結果
{'label_1': 'sample_func_1({arg})', 'label_2': 'sample_func_2({arg})'}
 
func_dict['label_1']
# 実行結果
'sample_func_1({arg})'

expression = func_dict['label_1'].format(arg="'123'")
expression
# 実行結果
"sample_func_1('123')"


eval(expression)
# 実行結果
'123追加した文字列'

result = eval(expression)
result
# 実行結果
'123追加した文字列'

add_text = "result2="
text = add_text + expression
text
# 実行結果
"result2=sample_func_1('123')"

exec(text)
result2
# 実行結果
'123追加した文字列'
```
---

##（ 続編記事 ）

・ [「【@registerデコレータ使用篇】Pythonの関数を辞書（dict）のValueに格納して、Keyに応じた関数を呼出す」](https://qiita.com/Afo_guard_enthusiast/items/8864b08568fabae912e1)