Python : 既存関数をカリー化s

[ できるかな Python ] のコーナー


最近、Pythonにハマってるので、いろいろとやってみた!
ここでは実用になるかはさておき、Pythonで出来たら楽しいって事をやってみるだけのコーナーです。


今日は、関数のカリー化です。
カリー化については、Wikipediaでも見てくださいね。

世の中の人に聞くと・・・カリー化関数の作り方ばかりが引っかかりますね。
でも、それは、別にうれしくはないはずです!
だって、それでは使いみちがないから・・・
やりたい事は既存の関数がカリー化関数になってほしいという事ではないでしょうか?
では、いってみましょう!


<材料>
  • 引数を複数とる関数
  • lambda式
  • 特殊メソッド__call__()

<作り方のポイント>
  • __call__()の利用
  • 可変引数の利用
  • 引数展開の利用
  • lambda式の利用
  • 関数呼び出し時の引数エラー(TypeError)例外の利用

カリー化
from __future__ import annotations from typing import Callable import inspect class LikeCurry: def __init__(self, func: Callable[..., any], arglen: int | None = None) -> None: self.func = func self.arglen = arglen if arglen is None: argspec = inspect.getfullargspec(func) self.arglen = len(argspec.args) def curry(self, *args: any, **kwargs: any) -> Callable[..., any]: return lambda *a, **kw: self.func(*args, *a, **kw, **kwargs) def __call__(self, *args: any, **kwargs: any) -> any: arglen = len(args) print(f"{args=} {arglen=} {self.arglen=}") if arglen >= self.arglen: return self.func(*args, **kwargs) else: return LikeCurry(self.curry(*args, **kwargs), self.arglen - arglen) # def __call__(self, *args: any) -> any: # try: # return self.func(*args) # except TypeError: # return LikeCurry(self.curry(*args)) def main(): def add3(a, b, c, *, x): return a + b + c + x add3c = LikeCurry(add3) print(add3c(2,3,4,x=5)) print(add3c(2, x=5)(3,4)) print(add3c(2,3)(4)) print(add3c(2)(3)(4)) if __name__ == "__main__": main()

LikeCurry()に関数を渡すとカリー化された関数風味のオブジェクトを返してくれます。
※ただし、カリー化の意味から考えても位置引数のみだよ!デフォルト値のある関数はうまく動作しないでしょう!

後は関数っぽく使えば・・・・



はい、美味しく出来ました!!!


何が嬉しいのかって?
それは、人それぞれです(笑)


(更新) さらに、美味しく出来ました!
try-exceptによるロジックをやめました!ちょっとオーバーヘッドが減るかもです★
keyword引数付き関数も使えるようになりました。ただし、最後の位置引数の呼び出しの前までにkewword引数は渡しておく必要があるよ!

コメント

このブログの人気の投稿

Kubuntu22.04 VirtualBox - 重大なエラー 〜 嘘でした"Document is enpty."なだけ

Pythonのソースファイルの行番号を取得したい

Raspberry Pi 3 シリアルコンソール&シリアル通信