doc.dev1x.org

reduce関数によるパイプライン処理パターン

1. 背景

シェルスクリプトのパイプ的な処理を書きたい

2. 課題

関数のネストは読みにくい

def run(value):
    return f3(f2(f1(value)))

3. 解決策

reduce関数にデータと関数のリストを渡す

def pipe(value, *fns):
    return reduce(lambda v, f: f(v), fns, value)
p = pipe(
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    fn1,
    fn2,
    fn3,
    fn4,
)
print(p)

4. メリット

関数を直列して実行する処理をパイプのように記述することができる

5. デメリット

初見では挙動を想像しにくい

条件分岐に対応できない(しづらい)

def run(value):
    v1 = pipe(
        value,
        fn1,
        fn2,
        fn3,
    )
    v2 = branch(v1)
    print(v2)

def branch(value)
    if value == xxx:
        result = pipe(
            value,
            fn4,
            fn5,
            fn6,
        )
    else:
        # 条件にマッチしない場合 fn4 をスキップする
        result = pipe(
            value,
            fn5,
            fn6,
        )
    return result

6. 注意事項

正直なところ完全に趣味の領域である

テンポラリ変数がベターな選択肢

def run(value):
    result1 = f1(value)
    result2 = f2(result1)
    result3 = f3(result2)
    return result3

参考資料

Appendix-1 素直にループで書いた例

def pipe(value, *fns):
    buffer = value
    for fn in fns:
        buffer = fn(buffer)

    return buffer

def main():
    result = pipe([...], fn1, fn2, fn3)
    print(result)