Pythonにswitch文無いんですか！？

# PythonはマジでSwitch文が無い

仕事などでちょくちょくPythonのスクリプトを書くのですが、先日、今までPythonをやってて一番衝撃的な事実が…。

**「PythonはSwitch文無ぇから、やりたかったらif文連ねやがれ」**

普段はShellscriptorであり、VBAerなわたくしがSwitch!Switch!言うのもおかしいですが(CaseとSelect...)、
いやいや、いくら何でもif文列挙しまくるのって見た目綺麗じゃないよね？！と思い、代替方法を考えた次第。

# 実装したい処理その1 - 文字列単純比較で条件分岐
では、お題に沿ってbashのケースとPythonのケースを考えてみましょう。
まず、ダメ外人の名前を入力すると、フルネームで答えてくれるスクリプトを作ります。
bashでいうところの以下のような感じ。

```bash:suketto.sh
case ${player} in
    "kinkade")
        echo "Michael Arthur Kinkade"
        ;;
    "mench")
        echo "Kevin Ford Mench"
        ;;
    "conrad")
        echo "Brooks Litchfield Conrad"
        ;;
    *)
        echo "Marcos Vechionacci"
        ;;
esac
```

これをPythonのifでいくとすると以下。

```py3:suketto.py
if player is 'kinkade':
    print("Michael Arthur Kinkade")
elif player is 'mench':
    print("Kevin Ford Mench")
elif player is 'conrad':
    print("Brooks Litchfield Conrad")
else:
    print("Marcos Vechionacci")
```

フローは分かり易いんですが、なんか文字ごちゃごちゃしてるし無骨な印象を受けます。

いや待てよ**「キーワードに対してそれに紐づく値を返す」**って、**やりたいことがまんま辞書**ではないか！ということで

```py3:suketto2.py
suketto = {
    "kinkade": "Michael Arthur Kinkade",
    "mench":   "Kevin Ford Mench",
    "conrad":  "Brooks Litchfield Conrad"
}
dame_gaijin = suketto.get(player,"Marcos Vechionacci")
```

get()は辞書の中から第一引数のキーを探し、ある場合はそのキーに紐づく値、無い場合は第二引数を返す関数です。
辞書型でやるとすっきり見える気がします。処理部分はワンライナーです。*でもベキオナチが若干浮いてる。*

# 実装したい処理その2 - 文字列曖昧比較で分岐
実装１ではダメ外人の名前を入れたらフルネームで答えてくれましたが、ダメ外人の名前が出てこない可能性だってあります。
「あいつなんやっけ、k...k...」「キンケード！！」と答えてくれた方がありがたいですよね。

シェルスクリプトは地味に優秀なので、条件にワイルドカード等が使えます。

```bash:suketto_z.sh
case $player in
    k*)
        echo "Michael Arthur Kinkade"
        ;;
    m*)
        echo "Kevin Ford Mench"
        ;;
    c*)
        echo "Brooks Litchfield Conrad"
        ;;
    *)
        echo "Marcos Vechionacci"
        ;;
esac
```

Pythonの辞書のキーにワイルドカードは使えませんので、これは考えねばなりません。
ということで、正規表現対応版は以下。
*なお、コメントで辞書の順序性について言及がありましたので、OrderedDictを使うようにしました。
コメントありがとうございました！*

```py3:suketto_z.py
import re
from collections import OrderedDict
def switch(player):

    suketto = OrderedDict((
        ("c.*", "Brooks Litchfield Conrad"),
        ("k.*", 'Michael Arthur Kinkade'),
        ("m.*", "Kevin Ford Mench"),
        (".*",  "Marcos Vechionacci")
    ))
  
    for k,v in suketto.items():
        if re.search(k,player):
            return v

dame_gaijin = switch('c')
```

もはやswitchという関数を作って中でごちゃごちゃやるしかなくなりました。
辞書のキーに正規表現用の文字列を準備し、それをループして与えられた選手名と比べ、
マッチした時点でreturnしてフルネームを返してます。(ループ中のreturnは超いまいちですが。)
想定しないものが引っ掛からないようにするためには、正規表現を頑張らないといけませんね。

なお、lambdaとかで強引に圧縮したものは以下になります。
リストの0番を返すことで、疑似的に最初にマッチしたものを取り出すようになってます。

```py3:suketto_z2.py
import re
from collections import OrderedDict
suketto = OrderedDict((
    ("c.*", "Brooks Litchfield Conrad"),
    ("k.*", 'Michael Arthur Kinkade'),
    ("m.*", "Kevin Ford Mench"),
    (".*",  "Marcos Vechionacci")
))
dame_gaijin = (lambda player: [v for k,v in suketto.items() if re.search(k,player)][0])(player)
```

**またもやワンライナーでいけました。いとやんごとなし。**

# PythonはSwitch文無いけど工夫次第
結局のところ、PythonではSwitch文が無くてもそこそこわかり易い分岐が書けました。
だからこそ、Switch文は実装されていないんでしょうね。
にしても、正規表現での分岐が一行でかけるとか、Pythonは**シェル芸人**の為にあるんでしょうか…。
*え？可読性？食べたことないです(笑)*

追記：
@shiracamus さんにコメントでご教示頂いたコードが今のところ一番スッキリしてますね。奥深…。

```py3
import re
suketto = (
    ("c.*", "Brooks Litchfield Conrad"),
    ("k.*", 'Michael Arthur Kinkade'),
    ("m.*", "Kevin Ford Mench"),
    (".*",  "Marcos Vechionacci")
)
dame_gaijin = lambda player: next(v for k,v in suketto if re.match(k,player))
```