printデバッグをpythonで行う場合、以下のように書くことが多いのではないだろうか。
print("hoge = " + str(hoge))
しかしわざわざダブルクォーテーションで囲ったりstr()
を用いたりするのは面倒である。
そこで、pythonインターフェースを開いたら、以下のようなchkprint
関数を記述しておくと良い。
1. 実装
def chkprint(*args):
flg = 1
for obj in args:
for k, v in globals().items():
if id(v) == id(obj):
target = k
break
if flg == 1:
out = target+' = '+str(obj)
flg = 0
else:
out += ', '+target+' = '+str(obj)
print(out)
この関数を一番最初に定義しておくだけ。
(※2017/06/07追記 : 上記の関数はグローバル変数にしか対応していません。shiracamusさんのコメントに書かれている関数がローカル変数にも対応しているので、ここに記載します)
from inspect import currentframe
def chkprint(*args):
names = {id(v):k for k,v in currentframe().f_back.f_locals.items()}
print(', '.join(names.get(id(arg),'???')+' = '+repr(arg) for arg in args))
2. 挙動
def chkprint(*args):
flg = 1
for obj in args:
for k, v in globals().items():
if id(v) == id(obj):
target = k
break
if flg == 1:
out = target+' = '+str(obj)
flg = 0
else:
out += ', '+target+' = '+str(obj)
print(out)
if __name__=="__main__":
a = 1
lst = [3, 1, 4, 1, 5]
chkprint(a)
chkprint(lst)
chkprint(a, lst)
a = 1
lst = [3, 1, 4, 1, 5]
a = 1, lst = [3, 1, 4, 1, 5]
こんな感じになる。
長いコードを動かしている途中でprintデバッグをはさみたくなった時、このchkprint
関数は手軽に「変数名」と「その変数の中身」を同時にprintしてくれるので、とても便利であると思われる。
3. 詳細
上記の関数で、一体何をやっているのかの説明。
for k, v in globals().items():
if id(v) == id(obj):
target = k
break
この部分はすべて、変数obj
を"obj"
という文字列に変換するためのものである。
globals()
とは、グローバル変数の一覧を辞書として返す「組み込み関数」である。
>>> globals()
{ '__name__': '__main__', 'a': 1, 'lst': [3, 1, 4, 1, 5], '__package__': None,
'__builtins__': <module 'builtins' (built-in)>, '__doc__': None, '__spec__': None}
この中でv
のid
がobj
のid
と一致した場合には、その時のkの値が変数名の文字列、ということになる。
(id()
を付けているのは、「中の値はobj
と同じだけれども変数名はobj
と異なるような変数」が拾われてしまうのを避けるためである)