Python.use(better, src=”PyPy”) #018: ハリウッドの原則
|中級篇|
Python.use(better, src=”PyPy”) # ソースコードの歩き方《復刻版》
ソースコードの歩き方《PyPy1.2》
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
》作業中です《