Search code examples
pythonpython-3.xlambdafunctools

Using partial with a conditional default argument


I'm using partial on a library function to supply it with a default value for one of the parameters

library_func = lambda x, y, z : x + y + z

my_func = functools.partial(library_func, z = 5) #default value for one of the variables
# equiv to lambda x, y : x + y + 5

Now suppose that instead of a constant default z, I want z to be dependant on the value of y. e.g., we look z up in a dictionary with keys that are different values of y.

z = {"1":7,"2":8}[str(y)]

# now my_func(x,y) = library_func(x,y,z = f(y))

Is that even possible? In my use case I've got a class holding a connection to a database (self.engine)

    self.engine = sqlalchemy.create_engine(connection_string)
    self.read_sql = partial(pd.read_sql, con = self.engine)

and pd.read_sql has a signature like pd.read_sql(con , name, columns ...)

I'd like to make a default value for columns which is dependent on the value of name passed.

I've thought about

self.read_sql = partial(pd.read_sql, con = self.engine, columns = lambda name: self.name_to_column_dict[name])

but get errors (for good reason!)


Solution

  • You can use a wrapper function instead:

    def my_func(x, y):
        return library_func(x, y, {"1":7,"2":8}[str(y)])
    

    Or if you don't want to retype all the keyword arguments as you suggested in the comment, you can use inspect.signature to obtain the signature of your wrapper function and then bind the arguments being passed in to the parameters so you can access them with dict keys, no matter if the arguments are passed in as positional arguments or as keyword arguments:

    import inspect
    
    def my_func(*args, **kwargs):
        bound = sig.bind(*args, **kwargs)
        bound.apply_defaults()
        return library_func(**bound.arguments, z={"1":7,"2":8}[str(bound.arguments['y'])])
    
    sig = inspect.signature(my_func)