简体   繁体   中英

Argument Unpacking while Defining Function in Python

I am trying to pass a list into the definition of a function in order to create new variables. The use case here is to run scipy's curve fit to find optimal parameters of the function. I want this function to be able to take any number of variables dynamically without specifically typing in all the variables I want it to optimize/solve for (b1, rate_1, etc.). Right now I have a list of the variables to include but can't seem to get the function to create them as new parameters in the function definition, which it looks like I need to do.

I'm familiar with using * in a function as seen below, but it seems that is for when the function is already defined and you're calling it. I want to do something similar but in the definition of the function so the function itself recognizes b1, rate_1, etc. as parameters that it can solve for using curve_fit.

My starter code:

def get_optimal_adstock_multivariate(x_var_names):
   y = np.array(final_df['Count Of Solutions'])
   # make list of coefficient variables (b1, b2, etc.) and make new variables for each rate (rate_1, rate_2, etc.)
   coef_vars = []
   rates = []
   for i in range(0, len(x_var_names)):
      coef_vars.append("b" + str(i+1))
      rates.append("rate_" + str(i+1))
   coef_vars_rates = coef_vars + rates

   def f(final_df, b0, *coef_vars_rates): # using * to pass b1, rate_1, b2, rate_2, etc. as parameters (unpacking the list)
      # need this function to recognize final_df, b0, b1, rate_1, etc. as variables

You cannot directly make the function recognize these variables unfortunately. You can use keyword arguments with a double-* and address them from the resulting dictionary object:

def f(a, b, **kwargs):
    ... kwargs["b0"] ...

Posting this in hope that it might help you, though I am aware it's not a full solution to your problem.

I don't understand what you are trying to do with x_var_names .

We can define equivalent functions:

In [260]: a, b, c = 1,2,3
In [261]: def foo0(x, *args):
     ...:     print(x, args)
     ...: 
In [262]: def foo1(x, a,b,c):
     ...:     print(x, a,b,c)
     ...: 

and call them a list of variables or the actual variables:

In [263]: alist=[a,b,c]
In [264]: foo0(100,*alist)
100 (1, 2, 3)
In [265]: foo1(100,*alist)
100 1 2 3
In [266]: foo0(100,a,b,c)
100 (1, 2, 3)
In [267]: foo1(100,a,b,c)
100 1 2 3

Or if I refine the print in foo0 I get the same display in both:

In [268]: def foo2(x, *args):
     ...:     print(x, *args)
     ...: 
In [269]: foo2(100,a,b,c)
100 1 2 3

Look at curve_fit . It will work with either foo1 or foo2 signatures.

f(xdata, *params)

The number of params is determined by p0 , though it also talks about determining them by introspection. By that I think it can deduce that foo1 expects 3 values.

Don't confuse variable names in the global environment with the variables, or tuple of values passed via curve_fit to your function. Local names can also be different. For example

def foo3(x, *args):
    a,b,c = args
    print(x, a,b,c)

uses local unpacking, where the a,b,c are just convenient ways of referencing the values in the function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM