Python3.0でswitch文を作りました

エイプリルフールなので嘘みたいなことをやってみた。

for x in range(5):
    print(x)
    MESSAGE = "The value is"

    class _(switch(x)):
        @case(0)
        def _():
            print(MESSAGE, "zero!")

        @case(1)
        def _():
            print(MESSAGE, "one!")

        @case(2)
        def _():
            print(MESSAGE, "twei!")

        @case_else
        def _():
            print(MESSAGE, "something else!!")

MESSAGEはちゃんと外のスコープを見れていることを示すためにあえてclassの外に置いてみた。まあnested_scopes以降なら動いて当たり前なのだけど。

実行するとこうなる。

0
The value is zero!
1
The value is one!
2
The value is twei!
3
The value is something else!!
4
The value is something else!!

実装はこちら:

def switch(val):
    case.cases = []
    case_else.func = lambda :None

    class SwitchMetaclass(type):
        def __init__(cls, name, bases, dct):
            if not case.cases: return
            for (v, func) in case.cases:
                if v == val:
                    func()
                    break
            else:
                case_else.func()
                

    class Switch(metaclass=SwitchMetaclass): pass
    return Switch

def case(x):
    def foo(f):
        case.cases.append((x, f))
    return foo

def case_else(f):
    case_else.func = f

メタクラスのコンストラクタ__init__は、メタクラスインスタンス(つまりクラス)がインスタンシエイトされるタイミングで呼ばれるので、デコレータで関数と値のマッピングを作っておいてそのタイミングでマッピングから順にマッチするものを探して実行するってだけ。

このまえid:moriyoshi に言われた「class Foo(lambda: ...)で何か実用的なことができないか」をやろうとしていたのだが、結局lambdaじゃないものになってしまった。