Python.use(better, src=”PyPy”) #017: クラス visitor.ASTVisitor

中級篇

Python.use(better, src=”PyPy”) # ソースコードの歩き方《中級篇》
ソースコードの歩き方《PyPy1.2》

《著》小粒ちゃん@湘南組、小粒ちゃん@博多組《監修》小泉ひよ子とタマゴ倶楽部
第1版♪2008/11/25 ● 第2版♪2010/04/29

PyPy1.2 のリリースを機に、PyPy1.1 版を再構成しました。
※ compiler の傘下にあるモジュールは、PyPy1.1.0 からの変更はありません。


クラス visitor.ASTVisitor

■ 組み込み関数 getattr:動的な問題解決を視野に

呼び出すべきメソッドを実行時に確定できると、動的な問題解決が視野に入ってきます。すると、ハードコーディングの呪縛から解かれ、要求仕様の変更にも柔軟に対処できます。

$ cat compiler/visitor.py 
...
class ASTVisitor:
    ...
    def dispatch(self, node, *args):
        self.node = node
        klass = node.__class__
        meth = self._cache.get(klass, None)
        if meth is None:
            className = klass.__name__
            meth = getattr(self.visitor, 'visit' + className, self.default)
            self._cache[klass] = meth
        return meth(node, *args)


メソッド dispatch は、

    def dispatch(self, node, *args):
        ...
        return meth(node, *args)

指定された引数をそのまま使って、その状況に最適なメソッド meth に処理を委ねます。このとき、meth は、実引数 node に応じて確定(変化)するので、動的な問題解決が視野に入ってきます。

            meth = getattr(self.visitor, 'visit' + className, self.default)

組み込み関数 getattr を利用すると、文字列(第2引数)で指定した属性が得られます。局所変数 className は、実引数 node のクラス名を反映しているので、得られるメソッド meth も対象のノード node を反映したものになります。たとえば、対象の AST ノードが式 Expression なら、実際にはメソッド visitExpression を呼び出します。


visitor は構文木を渡り歩きながら、依頼を的確に遂行していくでしょう。その仕事は、ゴルゴ13が組織の中から獲物を探し出して、一発で仕留める様に似ています。仕事の依頼がいつ、誰からなされたのかを、知る由もありません。

《HELP》組み込み関数 getattr

Python 3.1 (r31:73578, Jun 27 2009, 21:49:46) 
>>> help(getattr)
Help on built-in function getattr in module builtins:

getattr(...)
    getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.

■ メソッド default:規定の処理

visitor に期待されるメソッド visit? が見つからないときには、規定の処理 self.default を遂行します。メソッド default は、

$ cat compiler/visitor.py 
...
class ASTVisitor:
    ...
    def default(self, node, *args):
        for child in node.getChildNodes():
            self.dispatch(child, *args)

指定されたノード node の傘下にある、子ノード child を渡り歩きながら、木構造に沿って再帰的に処理 dispatch を繰り返します。


TOP
》作業中です《


関連記事

Last updated♪2010/05/18