実録 Debug
朝散歩していると、ちゃりんこに乗った小学生の一団に出合った。通学時間をとっくに過ぎているのに なんで、こうまとまってちゃりに乗っているんだろう?
いぶかしながら歩いていると、交差点のそこかしこに、おまわりさんやら、地区の交通指導員と おぼしき人が、黄色い旗を持って、交通整理をやっていた。田舎なんで、信号機の無い交差点が 多いから、事故でも起こっては困るという配慮だろう。
子供達は、体操着にヘルメットと言ういでたち。ヘルメットは、通学の時にかぶるのやら、保安帽 みたいのやら、サイクリングの時にかぶるのやら、はては、競輪選手みたいにかっこいいのやらと 色々。ちゃりも色々。ままちゃりを小さくしたのやら、サイクリング用やら、レーサータイプの ものまで。
次の日、別の小学校の前を通ったら、グランドが銀輪と黄色い歓声で溢れてた。そうか、春の一斉 交通安全週間なんだな。それぞれの学校で日程をずらして、交通安全の指導をしてるんだ。 暫く見てたら、一斉にちゃりの一団がグランドを出発していきましたよ。一瞬、ここは中国ですか と、思っちゃったぞ。
昔々、北京とやらへ行った事があるけど、朝の通勤・通学時間帯はちゃりが溢れていましたねぇ。 自動車よりもチャリ優先。交差点の真ん中でおまわりさんが、交通整理をしてたなあ。で、おいらも 早速泊まっていたホテルでチャリを借りて、中国人に成り済ましたのでした。どこまで走っても、 真平らで気持ちよく走れたよ。懐かしいね。
そろそろ、ちゃりを転がすにはいい季節だ。久しぶりに走ってみようかな。この地、結構登りが きつくて、ヘトヘトになるかもです。
(林檎の樹観察日記) 若々しい色の芽が出てきた。次は花だな。何時咲くのだろう。楽しみ!
Errorを知れ
Pythonを使ってグラフを書いてみるシリーズもこれで3回目。いいかげん飽きてきたので、今回で打ち止めに しょうと思う。そんな訳で、きっかけになったアンテナアナライザーのソフト説明書を改めてみたら、 リターンロスの表示なんてのが目に入ってきた。どんなものか、やってみる。
前々回だったか、csvモジュールでCLのリーダーマクロみたいな事が出来ればいいね、なんて事を書いた。 そんな事が出来るか調べてみたんだけど、どうもそこまで尖がった機能は無いようだ。あるのは、EXCEL方言 で読み込むとか、パスワードファイルをcsvファイルと看做して読むとか、そんな文字列操作だけだ。
だったら、ちょいと手を加えて、getlogの中に押し込めちゃおう。押し込める機能は、csvもどきを読み込んで 結果を、周波数、インピーダンスの形にするやつ。書いてみた。
def getlog(csv_file): with open(csv_file) as fd: s = fd.readlines() frx = [x for x in s if re.match(r"^\d.*", x)] return [(float(x[0]), complex(float(x[1]), float(x[2]))) for x in frx]
そして、pythonのプロンプト上で走らせたら、見事にエラーだよ。
Traceback (most recent call last): File "C:/homes/WORK/loss.py", line 39, in <module> if __name__ == '__main__': main() File "C:/homes/WORK/loss.py", line 33, in main fz = getlog('AA30.log') File "C:/homes/WORK/loss.py", line 14, in getlog return [(float(x[0]), complex(float(x[1]), float(x[2]))) for x in frx] ValueError: could not convert string to float: .
>>> import pdb >>> pdb.pm() > c:\homes\work\loss.py(14)getlog() -> return [(float(x[0]), complex(float(x[1]), float(x[2]))) for x in frx] (Pdb) p x '6.900000,60.95,-38.11\n' (Pdb) q
こういう時は、慌てず騒がず、pdbと言うPython用のdebuggerを呼び出して(importして)、エラーの 原因を解析すれば良い。効を焦りすぎて、csvでパースするのを忘れておったわい。
def getlog(csv_file): with open(csv_file) as fd: s = fd.readlines() frx = csv.reader([x for x in s if re.match(r"^\d.*", x)]) return [(float(x[0]), complex(float(x[1]), float(x[2]))) for x in frx]
上記のように修正したよ。
全体のDebug
修正して走らせてみたら、グラフが表示されなかったよ。虫が一匹見つかると他に居るぞって戒めは 当たっているね。(感心してる場合か!) 但し、Pythonからは何のお咎めも無し。こういう時は、pdbを普通に使ってみる。そう、rubyでdebuggerを 使うのと一緒の要領だ。
C:\homes\WORK>python -m pdb loss.py > c:\homes\work\loss.py(1)<module>() -> import re (Pdb) h Documented commands (type help <topic>): ======================================== EOF bt cont enable jump pp run unt a c continue exit l q s until alias cl d h list quit step up args clear debug help n r tbreak w b commands disable ignore next restart u whatis break condition down j p return unalias where Miscellaneous help topics: ========================== exec pdb Undocumented commands: ====================== retval rv (Pdb) h pp pp expression Pretty-print the value of the expression.
起動したら、pdbのプロンプトが出てきた。ppなんてコマンドが有るんか。
(Pdb) b main Breakpoint 1 at c:\homes\work\loss.py:26 (Pdb) c > c:\homes\work\loss.py(28)main() -> fz = getlog('AA30.log') (Pdb) l 23 g('set data style lines') 24 g.plot(dat) 25 26 B def main(): 27 #subprocess.call(['ttpmacro', 'sa.ttl']) # sa.ttl must be in teraterm-dir 28 -> fz = getlog('AA30.log') 29 dat = map(loss, fz) 30 graph(dat) 31 raw_input('Please press return to end...\n') 32 33 # when executed, just run main():
普通に、mainへbpを置いて継続実行してみた。なお、-> は、止まってる場所ね。B は、bpが設定されてる 行か。CUIだと苦労してるね。
(Pdb) n > c:\homes\work\loss.py(29)main() -> dat = map(loss, fz) (Pdb) n > c:\homes\work\loss.py(30)main() -> graph(dat)
ちょっと先へ進めてから、gnuplotの表示ルーチンへ渡すデータを確認
(Pdb) pp dat [(6.9, 9.4216182063861584), (6.904, 9.490277388103129), (6.908, 9.6853712081378944), : (7.292, 6.0375391405844052), (7.296, 5.9975322990725797), (7.3, 5.946130964684496)]
特にデータには異常なさそうなので、表示ルーチンへ下りて行きます。
(Pdb) s --Call-- > c:\homes\work\loss.py(20)graph() -> def graph(dat): (Pdb) s > c:\homes\work\loss.py(21)graph() -> g = Gnuplot.Gnuplot(debug=1) (Pdb) r gnuplot> set terminal windows gnuplot> set title "AA-30 Return loss" gnuplot> set data style lines gnuplot> plot "c:\\users\\foo\\appdata\\local\\temp\\tmp35pan5.gnuplot" notitle --Return-- > c:\homes\work\loss.py(24)graph()->None
s(tep)コマンドを使ったら、モジュールの中まで入って行ってしまいましたので、rを使って、呼び出しの 最後まで、ザーと実行しました。そしたら、不思議な事にグラフが表示されましたよ。これが噂のdebuggerを 動かすとBugが引っ込んじゃうと言う奴ですか。
(Pdb) where c:\python27\lib\bdb.py(383)run() -> exec cmd in globals, locals <string>(1)<module>() c:\homes\work\loss.py(34)<module>() -> if __name__ == '__main__': main() c:\homes\work\loss.py(30)main() -> graph(dat) > c:\homes\work\loss.py(24)graph()->None -> g.plot(dat)
これ、呼び出し履歴ね。
更に、n(ext)で実行を続けると、raw_inputを呼び出した所で、グラフが消えましたよ。こりゃ、raw_input の呼び出しを、graphの中へ持って行って、表示用のテンポラリーファイルが残るようにしないと、だめだな。 それに、plotを抜けた時に、表示のインスタンスが消されちゃう大問題が有るからね。
で、最終的に出来上がったのがこれ
import re, csv, subprocess from numpy import * import Gnuplot def getlog(csv_file): with open(csv_file) as fd: s = fd.readlines() frx = csv.reader([x for x in s if re.match(r"^\d.*", x)]) return [(float(x[0]), complex(float(x[1]), float(x[2]))) for x in frx] def loss(fz): f,z = fz return f, -20 * log10(abs((z -50) / (z + 50))) def graph(dat): g = Gnuplot.Gnuplot() g.title('AA-30 Return loss') g('set data style lines') g.plot(dat) raw_input('Please press return to end...\n') def main(): subprocess.call(['ttpmacro', 'sa.ttl']) # sa.ttl must be in teraterm-dir fz = getlog('AA30.log') dat = map(loss, fz) graph(dat) # when executed, just run main(): if __name__ == '__main__': main()
要のmain()が綺麗になったな。データを読んで、計算して、表示する。read-eval-print の出来上がりですよ。 いつも、こう綺麗になればいいんだけどね。って言うか、これって何処にも隠れている、パターンだよ。 Gofをやる前に、これは押さえておきたいね。
ああ、それから関数型プログラミング HOWTO とPython 良い慣用句、悪い慣用句には、眼を 通しておいた方が良いな。