3

For some reason, I can't get the variables passed in **kwargs in Python to be seen by the receiving function. (RESOLVED - see edit). This illustrates the problem - the **kwargs parameters are passed through several functions and make it to the integrand function. I put a print(kwargs) in there which displays the whole dictionary I created in the first few lines below. BUT these variables aren't seen by the integrand function and it errors out. What is the correct way to make these variables accessable to the final function? Much appreciated, searched quite a few posts on SO but couldn't find something directly relevant to my case.

def integrand(x, F, K, T1, T2, vol, flag):
    print(kwargs)
    d1 = (np.log(x / (x+K)) + 0.5 * (vol**2) * (T2-T1)) / (vol * np.sqrt(T2 - T1))
    d2 = d1 - vol*np.sqrt(T2 - T1)
    mu = np.log(F) - 0.5 *vol**2 * T1
    sigma = vol * np.sqrt(T1)
    value = lognorm.pdf(x, scale=np.exp(mu), s=sigma) * (flag * x*norm.cdf(flag * d1) - flag * (x+K)*norm.cdf(flag * d2))
    return value

def integrate(x, w, a, **kwargs): 
    return np.sum(w*transform_integral_negative1_1_to_0_1(x, a, **kwargs))

def transform_integral_0_1_to_Infinity(x, a, **kwargs): 
    return integrand(a+(x/(1-x)), **kwargs) *(1/(1-x)**2); 

def transform_integral_negative1_1_to_0_1(x, a, **kwargs): 
    return 0.5 * transform_integral_0_1_to_Infinity((x+1)/2, a, **kwargs)

flag = current_opt[i,0]
F = current_opt[i,1]
K = current_opt[i,2]   
T2 = current_opt[i,3]
T1 = current_opt[i,4]
r = current_opt[i,5]
vol = current_opt[i,6]

a = 0
b = np.Inf
kwargs = {'flag':flag, 'F':F, 'K':K, 'vol':vol, 'T2':T2, 'T1':T1}
integrate(x, w, a, **kwargs)

And this is what is printed before it errors out print(kwargs):

{'F': 1.2075, 'flag': -1.0, 'K': 0.12509999999999999, 'T2': 0.068500000000000005, 'vol': 0.42999999999999999, 'T1': 0.041099999999999998}

And the error, despite K being defined above:

NameError: name 'K' is not defined

The solution was to define each input rather than extract each value from the dictionary... The **kwargs passed to the last function extracts all the keyword arguments automatically.

Matt
  • 2,602
  • 13
  • 36
  • mgilson's answer is perfect, I have closed this as a dupe of a similar post with more details. – Bhargav Rao May 31 '16 at 16:17
  • Try adding `K = kwargs['K']`, etc. – Brent Washburne May 31 '16 at 16:18
  • as a side note if you want to take specific arguments like `K` then take those specific arguments: `def integrand(x, F, K, T1, T2, vol, flag):...` you can still pass them as keywords but don't have to worry about `**` mechanics. (also can specify defaults for some / all of them) – Tadhg McDonald-Jensen May 31 '16 at 16:34

1 Answers1

5

**kwargs is passed as a dict to the function, it doesn't automatically populate the function's locals.

e.g.:

kwargs = {'K': 1}

def foo(**kwargs):
    print(K)

def bar(**kwargs):
    print(kwargs['K'])

foo(**kwargs)  # NameError
bar(**kwargs)  # Works Ok.
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • The easier way to do this is to define each variable in the `integrand` function above instead of accepting `**kwargs` as an input, then pass `**kwargs` to that function and it will unpack the keywords, eliminating the need to extract each value from the dictionary 1 by 1. That is the answer I was looking for!!!! – Matt May 31 '16 at 18:24
  • @Matt -- Yes, definitely easier that way. :) – mgilson May 31 '16 at 18:27