続 functools.partialでのカリー化について考えてみる

西尾泰和のブログ: Pythonでカリー化を見てしまったら満足できなくなった.


もともと

>>> f = lambda x, y: x ** y
>>> g = f(x=2)
>>> g(3)
8

こんな風に使いたかったのに

>>>g = functools.partial(f, x=2)
>>>g(3)
8

で満足してちゃいけない

コード

ていうことで早速コード

def curry(f):
    def curriable(*args, **keywords):
        if f.func_code.co_argcount > len(args) + len(keywords):
            return partial(f, *args, **keywords)
        else:
            return f(*args, **keywords)
    return curriable


デコレータすげぇ!!って思ったので自分も同じようにデコレータ関数を作ってみました.

解説です.

ユーザ定義関数には func_code っていうコードオブジェクトがあります.

うんで,コードオブジェクトには引数の数の情報とかが入っているのでそれを利用しています.

デフォルト引数をいぢるっていう手もあるんだけどうまくいかない処理系もあるみたいで断念しました.

そして実行結果

>>>f = lambda x, y: x ** y
>>>f = curry(f)
>>> f(2, 3)
8
>>> f(2)(3)
8
>>>


デコレータとして

>>> @curry
... def f(x, y):
...     return x ** y
...
>>> f(2, 3)
8
>>> f(2)(3)
8
>>>

残念なお知らせ

これ,ユーザ定義関数にしか使えない 。+゚・(ノロ`)・゚+。
ユーザ定義関数には属性としてコードオブジェクトがあるけど,組み込み関数にはない orz


で,組み込み関数でも使えるバージョンも考えてみた

def curry(f):
    def curriable(*args, **keywords):
        try:
            return f(*args, **keywords)
        except TypeError:
            return partial(f, *args, **keywords)
    return curriable


でもこのバージョンには問題がある
もともとの関数にデフォルト引数があるとぜんぜんダメ(>_<)
「引数の数はあってるけど型がおかしいよ!!」っていうときも TypeError を投げちゃうから期待通りの動きをしてくれない(>_<)


結局消化不良になっちゃった(ノ∀`)タハー