Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Currying in inversed order in python

Suppose I have a function like this:

from toolz.curried import *

@curry
def foo(x, y):
    print(x, y)

Then I can call:

foo(1,2)
foo(1)(2)

Both return the same as expected.

However, I would like to do something like this:

@curry.inverse # hypothetical
def bar(*args, last):
    print(*args, last)

bar(1,2,3)(last)

The idea behind this is that I would like to pre-configure a function and then put it in a pipe like this:

pipe(data,
    f1, # another function
    bar(1,2,3) # unknown number of arguments
)

Then, bar(1,2,3)(data) would be called as a part of the pipe. However, I don't know how to do this. Any ideas? Thank you very much!

Edit:

A more illustrative example was asked for. Thus, here it comes:

import pandas as pd
from toolz.curried import *

df = pd.DataFrame(data)

def filter_columns(*args, df):
    return df[[*args]]

pipe(df,
    transformation_1,
    transformation_2,
    filter_columns("date", "temperature")
)

As you can see, the DataFrame is piped through the functions, and filter_columns is one of them. However, the function is pre-configured and returns a function that only takes a DataFrame, similar to a decorator. The same behaviour could be achieved with this:

def filter_columns(*args):
    def f(df):
        return df[[*args]]
    return f

However, I would always have to run two calls then, e.g. filter_columns()(df), and that is what I would like to avoid.

like image 357
Xiphias Avatar asked Feb 02 '17 15:02

Xiphias


1 Answers

well I am unfamiliar with toolz module, but it looks like there is no easy way of curry a function with arbitrary number of arguments, so lets try something else.

First as a alternative to

def filter_columns(*args):
    def f(df):
        return df[*args]
    return f

(and by the way, df[*args] is a syntax error )

to avoid filter_columns()(data) you can just grab the last element in args and use the slice notation to grab everything else, for example

def filter_columns(*argv):
    df, columns = argv[-1], argv[:-1]
    return df[columns]

And use as filter_columns(df), filter_columns("date", "temperature", df), etc.

And then use functools.partial to construct your new, well partially applied, filter to build your pipe like for example

from functools import partial
from toolz.curried import pipe # always be explicit with your import, the last thing you want is import something you don't want to, that overwrite something else you use

pipe(df,
    transformation_1,
    transformation_2,
    partial(filter_columns, "date", "temperature")
)
like image 191
Copperfield Avatar answered Oct 19 '22 10:10

Copperfield