0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで合成関数を実装する

Last updated at Posted at 2024-02-21

動機

コードを書いているとよく

list(filter(map(...)))

みたいな関数が連続したものに出会います。
大抵コードは左上から読んでいくので, こうしたものもlist->filter->mapの順で読みたくなりますが, 実際は逆順に適用されるので混乱しやすいです。

cut hoge.tsv | uniq | sort

こんな感じでシェルスクリプトのように書けたら見やすいかなと思ったりします。

実装

class CompositableFunction:
    def __init__(self, function):
        self.function = function
    
    def __call__(self, *args, **kwargs): # ()を後ろにつけたときに呼ばれる.
        return self.function(*args, **kwargs)
    
    def __or__(self, other): # |演算子
        return CompositableFunction(lambda *args, **kwargs: other(self(*args, **kwargs)))
    
    def __ror__(self, other):
        return CompositableFunction(lambda *args, **kwargs: self(other(*args, **kwargs)))

呼び出すときは

newfunc = CompositableFunction(func) # 新しく関数オブジェクトを作る.

@CompositableFunction # デコレータで呼び出す.
def func(*args, **kwargs):
    pass

のような感じで使えます。
functools.partialで部分関数を定義すればもうちょっと使いやすいと思います。

サンプルコード

ls = [2, 1, 0]
sub = CompositableFunction(lambda arr, x: [i - x for i in arr])
@CompositableFunction
def mul3(arr):
    return [i * 3 for i in arr]

print((sub|mul3|sorted)(ls, 1))
# [-3, 0, 3]

問題点

関数を合成してしまうと, 元の関数の引数の名前が*args, **kwargsに置き換えられてしまうのでエディタとかが使いにくくなります。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?