Skip to content

Instantly share code, notes, and snippets.

@jrosell
Last active December 2, 2022 11:57
Show Gist options
  • Save jrosell/2a5ec18785dbdcfff73a471856f4bca3 to your computer and use it in GitHub Desktop.
Save jrosell/2a5ec18785dbdcfff73a471856f4bca3 to your computer and use it in GitHub Desktop.
How to implement function composition in Python like we do in R: x <- 2; add_three <- \(x) x+3; duplicate <- \(x) x*2; x |> add_three() |> duplicate() |> {\(x) paste0("Result: ", x) }() # Result: 10
from typing import Callable
from functools import reduce, partial
add_three = lambda x: x+3
duplicate = lambda x: x*2
#-------
ComposableFunction = Callable[[float], float]
def compose1(*functions: ComposableFunction) -> ComposableFunction:
return reduce(lambda f, g: lambda x: g(f(x)), functions)
def example1():
x = 2
call1 = compose1(add_three, duplicate)
print("Result example1:", call1(x))
#-------
def compose2(funcs, data):
prev_data = data
for f in funcs:
prev_data = f(prev_data)
return prev_data
def call2(data, functions):
pipeline = partial(compose2, functions)
return pipeline(data)
def example2():
x = 2
print("Result example2:", call2(x, [add_three, duplicate]))
#-------
if __name__ == "__main__":
example1()
example2()
@jrosell
Copy link
Author

jrosell commented Dec 1, 2022

The idea is to improve code readability avoiding;
x = add_three(2)
x = duplicate(x)

Or:
call = lambda x: duplicate(add_three(x))

Another approach by @multimeric, here:
https://github.com/multimeric/PipeChain#pipechain

@davidbp
Copy link

davidbp commented Dec 1, 2022

You can use partial to build a function conditioned on a list of functions to create a 'pipeline'. Then use this function that stores the list without any need to pass the list of functions, just the data).

from functools import partial

def pipe_data_over_funcs(funcs, data):
    prev_data = data
    for f in funcs:
        prev_data = f(prev_data)

    return prev_data


def build_pipeline(functions):
    pipeline = partial(pipe_data_over_funcs, functions) 
    return pipeline


add_three = lambda x: x+3
duplicate = lambda x: x*2

functions = [add_three, duplicate]
pipeline = build_pipeline(functions)

pipeline(2)

@jrosell
Copy link
Author

jrosell commented Dec 2, 2022

Thanks @davidbp. I've just updated my code adding your approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment