if と別れる50の方法《01》if/dict による解法(switch の代用表現)

記事一覧if 篇for 篇配列 篇

Python.use(better) # OOP への道 《Python3.1, Jython2.5.0, IronPython2.6.x》
if/dict による解法(switch の代用表現)

《著》真樹育未・後藤いるか・小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第0版♪1988/10/12 ● 第1版♪1993/05/23 ● 第2版♪2003/05/25

■ 概要

if/switch 文は多くの問題を抱え、OOP を実践するときの「障害」になります。

伝統的なC言語風の for 文や悪名高い switch 文、配列の呪縛から解かれ、オブジェクト指向プログラミング〔OOP〕の醍醐味を堪能するための準備を行います。

何が問題か

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

》作業中です《

Last updated♪09/07/09