Python.use(better, src=”PyPy”) #003: クラス pycodegen.Expression
|中級篇|
Python.use(better, src=”PyPy”) # ソースコードの歩き方《中級篇》
ソースコードの歩き方《PyPy1.2》
PyPy1.2 のリリースを機に、PyPy1.1 版を再構成したものです。
※ compiler の傘下にあるモジュールは、PyPy1.1.0 からの変更はありません。
クラス pycodegen.Expression
この先で迷子にならないように、謎を解く鍵を確認しておきます。
$ cat compiler/pycodegen.py
...
def compile(source, filename, mode, flags=None, dont_inherit=None):
...
gen = Expression(source, filename)
...
gen.compile()
# この行間を読み解くのが秘訣 (@.@)
return gen.code
メソッド呼び出し compile() をリターン値にはせずに、属性 .code を参照しているので、メソッド呼び出しの「副作用」が謎を解く鍵になります。そこで、メソッド compile の本体に歩を進めると、
$ cat compiler/pycodegen.py ... class Expression(AbstractCompileMode): mode = "eval" def compile(self): tree = self._get_tree() gen = ExpressionCodeGenerator(tree) self.code = gen.getCode()
確かに、属性 .code を再設定しているのが分かります。
《TIPS》コードの行間を読む:副作用を前提にしたコードは読み辛く、バグの温床になりがちです。その一方で、副作用を暗示した「阿吽の呼吸」を読み解く術も必要です。「アマ」グラマーには諸手を挙げてお勧めできませんが、「プロ」グラマーには「匠」を凝らす術が求められる場面も少なくありません。コードの行間を読めるようになると、ひと味違うプログラミングの「醍醐味」を堪能できます。□
■ 新たな謎の組織(ExpressionCodeGenerator)と出生の秘密
しかし、これですべての謎が解明された訳ではありません。ようやく追いつめた実行犯の背後には、謎の組織 ExpressionCodeGenerator の存在が…。よくある連続ドラマの展開にも似ています。ここでは、副作用をもたらす源泉が、新たな登場人物 gen の背後 getCode() に隠されているのが分かります。そして、物語は新たな展開へと続きます。
ところが、その謎解きには新たな鍵 tree が必要です。しかも、その鍵を握っているのは、自分 self が属する組織(クラス)だと知ります。メソッド _get_tree は、どこに隠されているのでしょう。
$ cat compiler/pycodegen.py
...
class AbstractCompileMode:
mode = None # defined by subclass
...
def _get_tree(self):
# 謎を解く鍵はここに ¬(@.@)
def compile(self):
pass # implemented by subclass
def getCode(self):
return self.code
実は、その鍵は自身のルーツ(先祖)にありました。つまり、親クラス AbstractCompileMode から継承した資産だったのです。
《TIPS》抽象メソッドの意味(意義):モジュール pycodegen には、次のように
class Expression(AbstractCompileMode): class Interactive(AbstractCompileMode): class Module(AbstractCompileMode):AbstractCompileMode の直系がいくつか存在します。
AbstractCompileMode - Expression - Interactive - Moduleすると、AbstractCompileMode の傘下にある子孫クラス(のインスタンス)はどれも、同じメソッド呼び出し _get_tree() に呼応して、異なる動作を示すものと期待されます。そのため、メソッド _get_tree の本体には、特定の子孫クラスに依存しない抽象表現だけを記述します。□
↑TOP
》作業中です《