PythonでLispのcondっぽくパターンマッチング(条件分岐) その2

昨日のつづき。ちょっとだけ進化させて、デコレータを使ってC言語のswitch 〜 case文みたく書けるようにしてみます


(まだまだ名前空間が汚染してますが、一足飛びにやらずに、まず1ステップだけ進めてみます)


条件式の境界テストと、関数の中身の単体テストが、それぞれ個別に行えてます。。。といいつつも、再帰だと、関数の単体テストが面倒なのですが。

単一のpythonファイルですがブロックごとにわけて表記


Condクラス

# -*- coding: utf8 -*-
from __future__ import print_function

class Cond(object):
    def __init__(self):
        self.condlist=[]  
    def __call__(self,*args,**kwargs):
        for c,f in self.condlist:
            if c(*args,**kwargs):
                return f(*args,**kwargs)
        else:
            pass
    #for decorator
    def case(self,cond):
        def _(f):
            self.condlist.append((cond,f))
            f.__case__=cond
            return f
        return _

フィボナッチ数列関数 (分岐)

_fib=Cond()

@_fib.case(lambda n,x1,x2:n==0)
def _fib_0(n,x1,x2):
    return 0

@_fib.case(lambda n,x1,x2:n==1)
def _fib_1(n,x1,x2):
    return x2
    
@_fib.case(lambda n,x1,x2:True)
def _fib_n(n,x1,x2):
    return _fib(n-1,x2,x1+x2)

#エントリーポイント
def fib(n):
    return _fib(n,0,1)

テスト

#条件のテスト
assert _fib_0.__case__(0,0,1)   and not _fib_0.__case__(1,1,2)
assert _fib_1.__case__(1,1,2) and not _fib_1.__case__(3,0,1) 
import random
assert _fib_n.__case__(random.randint,0,1)

#関数の中身のテスト
assert _fib_0(0,0,1)==0
assert _fib_1(1,0,1)==1
assert _fib_n(3,0,1)==2
#再帰の場合は、関数の中身の単体テストめんどくさい


#結合テスト
testcase=[0, 1, 1, 2, 3, 5,
          8, 13, 21, 34, 55,
          89,144, 233, 377, 610,
          987, 1597, 2584, 4181, 6765, 10946]

for i in xrange(len(testcase)):
    ret=fib(i)
    assert ret==testcase[i]
    print(i,ret)