2008年12月28日日曜日

つづき

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
で、ruleがhandlerを登録してcallbackしてもらうのはごく普通なのだが、ruleを書く側の立場として生活しやすいtrickがほしい。どういうことかというと

def hanlder(self):
classmembers = self.guessClassmember(klass)
for func in klass.findall('./Stmt/Function/'):
if self.isClassMethod(func):
continue
for assattr in func.findall('.//Assign/AssAttr'):
if self.isClassMemberAssign(assattr, classmembers):
print 'defined at', classmembers[assattr.attrib['attrname']].attrib['lineno']
print 'substitute at', assattr.attrib['lineno']

と書いていたのを

def calc(self):
classmembers = self.guessClassmember(klass)
for func in self.wait('.//Class/Stmt/Function/'):
if self.isClassMethod(func):
continue
for assattr in self.wait('.//Class/Stmt/Function//Assign/AssAttr'):
if self.isClassMemberAssign(assattr, classmembers):
print 'defined at', classmembers[assattr.attrib['attrname']].attrib['lineno']
print 'substitute at', assattr.attrib['lineno']

とかしたい。self.waitは実際にはxpath文字列じゃなくてxpathを与えて作ったhandlerにしないと、methodの評価のタイミングが呼び出されたときなので、xpathがvisitにわたらないので駄目かな?あ~でもcalcに制御がわたってwaitを読んだときにcalcから抜けてhandlerのcallbackでyieldしてforに戻ってくる構造だからなぁ。

pollingするための口と、pollした結果どのhandlerをfireするか決めればいいのか。pollingするとほかのruleのcalcを呼ぶ可能性がある。ひとひねりしないとpollingされる関数が再帰してstack over flowだ。multithreadで書くほうが自然に思えてきた。実際にvisitするobjectがいるthreadがproducerで、handerを登録するruleがいる側がconsumerだ。といいつつも、次にvisitするものは何かをconsumerから教えてもらわないといけない。(ここがyieldになる。)

yieldが戻り先から値を返してくれるとwaitのかわりにyieldしてあげればらくに書けそう。yieldでxpathを受け取り、見つかったときにその関数(calc)を、見つかったnodeとともに返してあげればいい。すくなくとも2.4だとできないのでyieldから戻ってきたときに持たせるvalueを書き込むスペースを用意してあげることになる。美しくないが、複雑なコントロールフローを作るよりはましだ。しかしfor文が

while True:
yield ".//Stmt"
r = getresult()
#do something with r here.

こんな感じになってしまうだろう。かなり個人的な趣味をいうと、PEPで提案されているyieldの括弧のつけ方はきらいだなぁ。yield(42)とかのほうがいい。関数呼び出しっぽいが。しかしexception関係といい、2.4のgeneratorは微妙だね。

あとxpathに先読み否定(要はclassmethodをチェックさせたい)とかあるともうちょっとエレガントになる。まあ、蛇足ですが。

0 件のコメント: