「PythonとC++で定数を共有したい,かつC++側の定数はコンパイル時に確定させたい,かつPythonでも同じ変数を使いたい」という特異な例があったのでメモ.
Pythonから.hで定義された
# ifndef _PARAM
# define _PARAM
# define NUM 10
# define epoch 100
# endif
と言うような定数を取り出す.今回は,const int
などで定義したグローバル変数は場合分けがめんどくさいので考えません.
def read_header_and_get_macro(header_filepath):
with open(header_filepath, mode='r') as f:
lst = [s.strip() for s in f.readlines()]
comment_flg = False
for l in lst:
items = l.split()
if len(items) != 0 and items[0] == "/*":
comment_flg = True
continue
if comment_flg == True:
if len(items) != 0 and items[0] == "*/":
comment_flg = False
continue
if len(items) < 2 or items[0] != "#define":
continue
if items[1] in globals():
if items[2] == 'true':
globals()[items[1]] = True
elif items[2] == 'false':
globals()[items[1]] = False
else:
try:
globals()[items[1]] = float(items[2])
except ValueError:
try:
globals()[items[1]] = int(items[2])
except ValueError:
globals()[items[1]] = items[2]
やっていること
lst = [s.strip() for s in f.readlines()]
ファイルを読み込んで行ごとにリストにする.今回は行ごとのリストをとってきてそれをリストで回したけど別にf.readline()
をfor文回すのは自由
comment_flg = False
C(++)では/*
から始まって*/
で終わるまでの間は全てコメントなので,これを覚えておくためのフラグ.
items = l.split()
行の中身について,半角スペースなどでわけられているところを分けたリストを取得.
['#define', 'NUM', '10']
みたいなリストがほしかった.
if len(items) != 0 and items[0] == "/*":
comment_flg = True
continue
if comment_flg == True:
if len(items) != 0 and items[0] == "*/":
comment_flg = False
continue
上記の通り,コメントを除く.
if len(items) < 2 or items[0] != "#define":
continue
#define
から始まらない行はマクロを定義していないので除く.
if items[1] in globals():
if items[2] == 'true':
globals()[items[1]] = True
elif items[2] == 'false':
globals()[items[1]] = False
else:
try:
globals()[items[1]] = float(items[2])
except ValueError:
try:
globals()[items[1]] = int(items[2])
except ValueError:
globals()[items[1]] = items[2]
今までのもの以外のものが定数のはずです.このとき, items[1]
には定数名が入っているはずなので,これがグローバル変数として定義されているかチェックするためにitems[1] in globals()
をします.もしも定義されていれば, globals()[items[1]]
でその値がわかるので,変数を強制的に書き換えれば完成.ですが,C++のbool型をPythonにそろえてあげる処理をしているのと,float/int/strの変換も行っています.