if と別れる50の方法《01》if/dict による解法(switch の代用表現)
Python.use(better) # OOP への道 《Python3.1, Jython2.5.0, IronPython2.6.x》
if/dict による解法(switch の代用表現)
■ 概要
if/switch 文は多くの問題を抱え、OOP を実践するときの「障害」になります。
伝統的なC言語風の for 文や悪名高い switch 文、配列の呪縛から解かれ、オブジェクト指向プログラミング〔OOP〕の醍醐味を堪能するための準備を行います。
■ 関連記事
- Java プログラマーのための Python 導入ガイド
- 例題で学ぶ Jython/Swing デザインパターン《Jython2.5》改訂版
- ゲームに学ぶ Jython/Swing フレームワーク《Jython2.5》改訂版
- IronPython で学ぶ WPF プログラミングの世界《IronPython2.6》改訂版
何が問題か
Java 言語の解説書 JPL には、伝統的な switch 文を利用した事例を紹介しています。しかし、switch 文はいくつかの問題を抱え、OOP を実践 するときの「障害」になりがちです。そこで、その問題点を明らかにするとともに、それを解消する術を紹介します。
事例:JPL, p.234
JPL の読者の多くは、以下の事例によって、switch 文を知ることになるでしょう。
■ switch の代用:if による解法
def hexValue(ch): # step 1 if (ch == "0" or ch == "1" or ch == "2" or ch == "3" or ch == "4" or ch == "5" or ch == "6" or ch == "7" or ch == "8" or ch == "9"): return ord(ch) - ord("0") if (ch == "a" or ch == "b" or ch == "c" or ch == "d" or ch == "e" or ch == "f"): return ord(ch) - ord("a") + 10 if (ch == "A" or ch == "B" or ch == "C" or ch == "D" or ch == "E" or ch == "F"): return ord(ch) - ord("A") + 10 raise Exception("non hex digit")
ここでは、実引数として与えられた文字 ch が、どの条件式 ch == "?" を満たすかを判定して、適切に処理します。すると、次のような発想が生まれます。
■ switch の代用:演算子 in による解法
def hexValue(ch): # step 2 if ch in "0123456789": return ord(ch) - ord("0") if ch in "abcdef": return ord(ch) - ord("a") + 10 if ch in "ABCDEF": return ord(ch) - ord("A") + 10 raise Exception("non hex digit")
演算子 in を導入すると、文字 ch が、どの集合(シーケンス)に属するかを、条件式 ch == "???" で判定します。文字 ch が、どの集合に属するか(what)は、集合の各要素と値を比較する(how)こと、つまり ch == "?" に他なりません。つまり、step2 では、それを実現する具体的な手段(how)に依存しない、その目的(what)だけを明示した「抽象表現」になっているのが分かります。
ここでは、演算子 == を用いて、文字列の値を比較していますが、それを実現する手段は状況に応じて変化することが予想されます。実際に、演算子 in の挙動は、クラスごとにいつでも自由に再定義できます。
step1 と step2 には、具象表現と抽象表現との違いはあっても、表現を代えただけの同意語です。同じ発想に基づくもので、本質的な違いはありません。すると、次のような発想が生まれます。
■ switch の代用:組み込み型 dict による解法
def hexValue(ch): # step 3 switch = { "0123456789": lambda ch: ord(ch) - ord("0"), "abcdef" : lambda ch: ord(ch) - ord("a") + 10, "ABCDEF" : lambda ch: ord(ch) - ord("A") + 10, } for k,v in switch.items(): if ch in k: return v(ch) else: raise Exception("non hex digit")
組み込み型の辞書 dict を導入すると、任意のキーと値との対によって、switch と同等の構造を実現できます。ここでは、キーに文字列(シーケンス)を、値にラムダ式を設定しています。
ここでは、実引数として与えられた文字 ch が、どの集合(シーケンス)に属するかを、演算子 in で判定します。この条件 ch in k を満たすなら、対応するラムダ式 lambda ch: ??? を評価 v(ch) した値をリターン値にします。
step2 と step3 には、辞書 dict を導入したという違いはあっても、他の抽象表現に代えただけの同意語です。同じ発想に基づくもので、step1 と本質的な違いはありません。
ここまで見てきたように、step1,2,3 はどれも「switch への未練を残したまま」表現を代えただけの「同義語」だと分かります。未練を断ち切って、新しい出会いを探してみましょう。幸せの青い鳥は、意外に身近な所にいるかもしれませんよ。(^.^)
Tips
》作業中です《