39
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-11-24

##1. メソッド(関数)を宣言する

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


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

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

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

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

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

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

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

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

Python3
func_dict['label_1']()

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

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

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

#####( 参考 )

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】辞書を利用して関数をまとめて実行する」
  2. 「[Python] **を用いたキーワード引数の辞書化」

##( 使いみち )

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

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

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

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

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

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

ファイルの拡張子を取得する

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ファイルからテキスト部分を一括抽出するメソッド」

##( 備考 )

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

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
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
func_dict['label_1']
# 実行結果
'abc追加した文字列'

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

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

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

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


##( 備考2 )

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

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

Python3
func_dict = {
    'label_1' : "sample_func_1({arg})",
    'label_2' : "sample_func_2({arg})"
    }
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に応じた関数を呼出す」

39
57
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?