Python(関数オブジェクトとクロージャー)

def my_sort(xs,function):
    """ソートを行う関数
       @param xs       ソートを行うリスト
       @param function ソート判定の関数オブジェクト
       @return tmplist ソート済みのリスト"""
    tmplist = xs.copy() # xs自身を書き換えると破壊的関数になる→他の環境を汚す
    n=len(tmplist)
    for i in range(n-1):
        swap_flag=False
        for j in range(1,n-i):
            if function(tmplist[j-1],tmplist[j]):
                tmplist[j-1],tmplist[j]=tmplist[j],tmplist[j-1]
                swap_flag = True
        if not swap_flag:
            break
    return tmplist

def test(a,b):
    is_str = lambda x:isinstance(x,str)
    is_num = lambda x:isinstance(x,(int,float))
    def validate(x):
        #if not is_str(x) and not is_num(x):
        if not (is_str(x) or is_num(x)):
            raise ValueError(f"{x}は数値でも文字列でもありません")
        
    validate(a)
    validate(b)
    # validate(a); validate(b) # このように書くこともできる

    if (is_num(a) and is_num(b)) or (is_str(a) and is_str(b)):
        return a>b
    #elif is_str(a) and is_num(b):
    #    return True
    else:
        return is_str(a) and is_num(b)

def invert(function):
    #def inverted_function(*args):
    #    return not function(*args)
    #return inverted_function
    return lambda *args: not function(*args)


print(my_sort([1,3,"ahg",-8,"king",5,7,"a",9,55,4.74,"world"],invert(test)))

ソート関数のプログラムですがラムダ式を用いて内部関数を定義したり、returnで条件の真偽値を返すことで効率化したり、考え方によって色々な書き方が可能です。

そもそもPythonで関数オブジェクトを渡して処理を行う高階関数の考え方や クロージャーとして外部の環境を受け取り、それを関数オブジェクトとして返す手法など、高級言語では普通に使われる考え方も、知らなければ低級言語の手法で物事を考えて処理しようとしてしまう…
考え方の幅を広げて柔軟な思考を身につけたいと思う今日この頃です。

考え方についての良い話を下記のリンクにて紹介
http://practical-scheme.net/trans/beating-the-averages-j.html
http://practical-scheme.net/trans/hp-j.html

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください