eval。
この組み込み関数は、文字列を指定された名前空間上で評価(実行)してくれるというありがたい関数だ。
pdb.pyを弄っていて知った。結構勉強になったな。
って、世間ではPythonに限らずこの手のは常識らしいが。
またおれだけ知らないのかよ…orz
で…こいつの使い道はと言えばたとえば俺の作っているgladeのXMLからのpyGtk用コンバータだと、
GtkWindowInfo
GtkVBoxInfo
などなど、と、XML上で表記されているクラス名末尾にInfoを付けたPythonクラスを作成して、そのクラスが自分のプロパティを解読してpythonコードに変換すると言う仕組みになっている。
ここで、以前は
1
2 def __generateInfo(self,name):
3 # 名前からクラスオブジェクトを生成する
4
5 if name == "GtkWindow":
6 return GtkWindowInfo(self.currentWidget)
7 else:
8 return WidgetInfo(self.currentWidget)
9
のようなコードを書いて、そんでそのつど生成してた。
こんなのだとクラスが増えるごとにメンテナンスの手間がかかるし、間違いも起きる。だいいち、頭悪そうなコードだ。(いや実際悪いけどな)
そこで、
1
2 def __generateInfo(self,name,parent):
3 # 名前からクラスオブジェクトを生成する
4
5 try:
6 return eval("%sInfo(parent)" % name)
7 except:
8 print "error in %s" % name
9 return WidgetInfo(parent)
とすれば、命名規則にしたがっている限りメンテ不用でオブジェクトが生成できるというわけだ。
そこで。ハマった、というのは何かといえば、上のコードで言えば当初、
parentをself.currentWidgetとしていたのだ。つまり
1
2 def __generateInfo(self,name):
3 # 名前からクラスオブジェクトを生成する
4
5 try:
6 return eval("%sInfo(self.current.Widget)" % name)
7 except:
8 print "error in %s" % name
9 return WidgetInfo(parent)
こうなっていたのだ。(追記:よく見るとこの時点で間違いが判るはず…)
gladeのXMLにおいて<child>タグ直前に生成したウィジェットをself.currentWidgetに代入してあるため、そいつが親ウィジェットになるという仕組みになっていた。
まあともかく、self.currentWidgetでは例外が出る…というか、全然ダメ。
もちろん、実際にはtry節のなかで呼んでいるので、ジェネリックなベースウィジェット生成クラスが呼び出されまくるということになっていたわけだが、ともかく、機能していない。
evalにglobals()とかlocals()とか渡してみてもダメ。
selfは鬼門なのだろうか?どういう引数を渡せばいいんだろう?
と考えたがわからなかったので、設計の方を変えて逃げた。
いずれ追求してみたいところではある。
って、再度調べてみたら普通にself.currentWidgetでOK。というわけで、追記ついでにvimのTOhtmlコマンドを駆使してリストを埋め込んでみた。普段こういう配色でやってます。まあそれはともかく。
なぜさっきはダメだったのか…アンドゥしまくって調べてみた。
結果。
self.current.Widgetとtypoしていた
orz
というわけで、再現リストも忠実にcurrent.Widgetにしておいた