Python.use(better, src=”PyPy”) #018: ハリウッドの原則

中級篇

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

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

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


ハリウッドの原則

■ 前順走査 preorder:構文木を渡り歩く

前順走査では「深さ優先」で構文木を渡り歩きます。

$ cat compiler/visitor.py 
...
class ASTVisitor:
    ...
    def preorder(self, tree, visitor, *args):
        """Do preorder walk of tree using visitor"""
        self.visitor = visitor
        visitor.visit = self.dispatch
        self.dispatch(tree, *args) # XXX *args make sense?


メソッド preorder は、

    def preorder(self, tree, visitor, *args):
        ...
        self.dispatch(tree, *args)

指定された引数をそのまま使って、構文木 tree を渡り歩くメソッド dispatch に処理を委ねます。このとき、

        visitor.visit = self.dispatch

引数 visitor のインスタンス属性 .visit には、その取るべき行動を規定しておきます。つまり、ここで visitor との契約(暗殺の依頼)が取り交わされていたのです。

《TIPS》ハリウッドの原則:多彩なメソッド visit? が定義されているのに、そのメソッドが呼び出されている箇所を探そうとしても、それは徒労に終わります。なぜなら、

    self.visit(...)

という形式のメソッド呼び出しに遭遇したら、その背後には dispatch に込められた思いがあるからです。同じコードの背後では、ノードごとに異なる「最適な」メソッドが呼び出され、その本体にあるコードの断片が実行されます。それを知ることはできませんし、それを知る必要もないのです。□

■ 関数 walk:はじめの一歩を踏み出したのは

そこで気になるのは、事件の発端です。とこかで、依頼主と実行犯とが遭遇しないかぎり、物語は始まらないのです。その謎を解く鍵は…。

$ cat compiler/visitor.py 
...
_walker = ASTVisitor
def walk(tree, visitor, walker=None, verbose=None):
    if walker is None:
        walker = _walker()
    if verbose is not None:
        walker.VERBOSE = verbose
    walker.preorder(tree, visitor)
    return walker.visitor


関数 walk は、

def walk(tree, visitor, walker=None, verbose=None):
    ...
    walker.preorder(tree, visitor)
    return walker.visitor

指定された引数をそのまま使って、構文木 tree を渡り歩く visitor に仕事を依頼するときの、状況 preorder を設定します。その物語を演出するのに不可欠なのが、脚本家たる walker の存在です。同じ原作でも、演出家や脚本家が異なれば、まったく異なる作品に仕上がる様に似ています。

■ 事件は現場で起こっている

すると、思い出されるのは、その証拠となる次の手掛かりです。

$ cat compiler/pycodegen.py 
...
class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
    ...
    def __init__(self, tree):
        ...
        walk(tree, self)

そこには、確かに関数呼び出し walk() の足跡が残っていました。


TOP
》作業中です《


関連記事

Last updated♪2010/05/18