PythonにてC言語の関数ポインタみたいなことをやってみる
あるプログラムをPythonで書くことがあり、関数を配列化するため、どうしてもC言語の関数ポインタのようなものを使いたくなった。その時の+αも含めた記録。結論的には、辞書を使うのがベターであった。
簡略化
小生の事例は多少ややこしいので、ここでは簡略化したものを例示。コマンドの引数としてキーおよびキーへの1文字のパラメータを与え、キーが'i'の場合、パラメータを数値でインクリメント(+1)、キーが'c'の場合、パラメータの文字をHexでインクリメントするもの(例:'A'をインクリメントして'B'を出力)。ソースコードを見た方が早い。なお、ここでは、関数配列という用語を用いることとした。
ソースコード
dic_func+alpha1.py
# -*- coding: utf-8 -*-
# Cの関数ポインタ(配列)をPythonで実現するサンプル+α
import sys
# 文字をインクリメントする関数(例:入力'A'に対する出力が'B')
def f_char_inc(arg):
val = ord(arg)+1
return chr(val)
# 数値をインクリメントする関数(+1)
def f_int_inc(arg):
val = int(arg)
return val+1
# 辞書による関数配列
f_dic = {'c': f_char_inc, 'i': f_int_inc}
# リストによる関数配列
f_list = [['c', f_char_inc], ['i', f_int_inc]]
### メインプログラム ###
# ”コマンド キー パラメータ”が実行形式
if len(sys.argv) != 3:
print('使用法: '+sys.argv[0]+' キー パラメータ')
print('キー: i:パラメータが数値 c:パラメータが文字')
print('ex: '+sys.argv[0]+' i 4')
sys.exit()
# キーおよびパラメータ取得(引数のエラーチェックなし)
key = sys.argv[1]
arg = sys.argv[2]
# 辞書利用
if f_dic.get(key) == None: # キーのチェック
print('該当するキーがありません') # キーが見つからず
sys.exit() # 終了
ret = f_dic[key](arg) # キーによる呼び出し
"""
# リスト利用
found = 0
for f in f_list: # forなどでループを回す必要あり
if key == f[0]:
found = 1
ret = f[1](arg) # リスト要素による呼び出し
break
if found == 0: # キーが見つからず
print('該当するキーがありません')
sys.exit() # 終了
"""
# 結果表示
print('戻り型: '+str(type(ret))+'\t戻り値: '+str(ret))
ソースコード内にコメントが記載されているので、基本的にはそちらを参照してほしいが、あえてさらなるコメントを下記。
- 関数を辞書の値部分に配置(配列化)。
- コメント化されているリストによる関数配列を利用すると、自らのコードでループして該当関数を探す必要がある。辞書による関数配列だと不要(Python内部的には類似のことを実施しているのであろう)。
- 関数配列の戻り値の型を統一する必要がない。異なる型を返すことができる。
検証
キーが整数('i')
python3 dic_func+alpha1.py i 6
戻り型: <class 'int'> 戻り値: 7
キーが文字('c')
% python3 dic_func+alpha1.py c G
戻り型: <class 'str'> 戻り値: H
エラー
% python3 dic_func+alpha1.py 0
使用法: dic_func+alpha1.py キー 引数
キー: i:引数が数値 c:引数が文字
ex: dic_func+alpha1.py i 4
%
% python3 dic_func+alpha1.py 0 R
該当するキーがありません
EOF