0

I have created a set of functions that call each other to price options. One of the functions runs for quite a while to optimize some parameters (using Nelder Mead). Within this function, a value is calculated, that I would like to use in some other functions, but I do not want to pass it out through the return statement. I thought using global var would be perfect.

Now, the weird part: When I load the functions I wrote as a package via import *, I cannot access the global var the one function creates. If I take the script with the function definitions, run it to define the functions in my Python console, and then call the functions, the global var construction works fine. What might be the issue and why does it make a difference whether I load/define the functions as a package or 'manually'?

Error when loading as package: NameError: name 'h_out' is not defined.

global h_out
h_out=None
import hngoption

prices = timeseries[data.Date[i]:].head(30)
output = hngoption.params(prices) 

params() calls function LogLike() as part of its computations which contains:

def LogLike(B, r):
        # (...)
        for i in range(N - 3, -1, -1):
            h[i] = B[0] + B[2] * h[i + 1] + B[1] * pow(Z[i + 1] - B[3] * sqrt(h[i + 1]), 2)
            Z[i] = (ret[i] - r - B[4] * h[i]) / (h[i] ** 0.5)
            L[i] = -log(h[i]+ 0.000000000000001) - (ret[i] ** 2) / h[i]

        LogL = VecSum(L)

        global h_out       #IMPORTANT PART
        h_out = h[0]

        if ((B[0] < 0) | (B[1] < 0) | (B[2] < 0) | (B[3] < 0) | (B[4] < 0)):  # (B[2]+B[1]*pow(B[3],2)>=1))

            return 1e50
        else:
            return -LogL  # Minimize -Log-Like(Beta)

Full LogLike function:

def LogLike(B, r):

    N = len(timeseries)  #timeseries is a global var
    # Calculate S&P500 returns
    ret = [0.0] * (N - 1)
    for i in range(0, N - 1):
        ret[i] = (log(timeseries.ix[i] / timeseries.ix[i + 1]))

    Variance = VecVar(ret)
    h = [0 * i for i in range(N - 1)]
    Z = [0 * i for i in range(N - 1)]
    L = [0 * i for i in range(N - 1)]

    # Construct GARCH(1,1) process by working back in time
    h[N - 2] = Variance
    Z[N - 2] = (ret[N - 2] - r - B[4] * h[N - 2]) / h[N - 2] ** 0.5
    L[N - 2] = -log(h[N - 2]) - (ret[N - 2] ** 2) / h[N - 2]

    for i in range(N - 3, -1, -1):
        h[i] = B[0] + B[2] * h[i + 1] + B[1] * pow(Z[i + 1] - B[3] * sqrt(h[i + 1]), 2)
        Z[i] = (ret[i] - r - B[4] * h[i]) / (h[i] ** 0.5)
        L[i] = -log(h[i]+ 0.000000000000001) - (ret[i] ** 2) / h[i]

    LogL = VecSum(L)

    global h_out       #IMPORTANT PART
    h_out = h[0]


    if ((B[0] < 0) | (B[1] < 0) | (B[2] < 0) | (B[3] < 0) | (B[4] < 0)):  # (B[2]+B[1]*pow(B[3],2)>=1))

        return 1e50
    else:
        return -LogL  # Minimize -Log-Like(Beta)
SW7
  • 9
  • 1
  • 5
  • 6
    Please don't give code in screenshots. Instead, post the code in the question itself, preferably code which constitutes a [mcve]. – John Coleman May 12 '17 at 15:47
  • 4
    You should also explain why you don't want to use return, since that is the obvious way to return data from a function. – Daniel Roseman May 12 '17 at 15:49
  • Mainly because a NelderMead calls this function and passing another argument out of the return will hugely complicate the chain of functions that call each other. – SW7 May 12 '17 at 15:57
  • Possible duplicate: http://stackoverflow.com/questions/41150391/python-3-the-visibility-of-global-variables-across-modules – tdelaney May 12 '17 at 15:59
  • Use `return` don't use global state. – juanpa.arrivillaga May 12 '17 at 16:01
  • When you do `import *` only the variable in existence at the point of import are visible. This is a special case of the rebinding of variables that happens with `import *`. I referenced a similar question, but it doesn't deal with the "imported too early" problem. – tdelaney May 12 '17 at 16:02
  • @juanpa.arrivillaga - global state is appropriate from time to time. OP looses the ability to run multiple copies of the code at the same time, but if that's not a design goal, then its okay. – tdelaney May 12 '17 at 16:03
  • Your question includes the function... which is most irrelevant except the part where it writes the global variable... but omits the importing script that has the problem. – tdelaney May 12 '17 at 16:09

2 Answers2

0

You can use following type of arguments that will carry the result.

def test(a):
    a[0]=a[0]+2

>>> a = [2]
>>> test(a)
>>> a
[4]
mangupt
  • 369
  • 2
  • 11
0

from somemodule import * binds the global variables in somemodule that exist at that time to like-named variables in the current module. Variables that have not yet been created are not imported. The current module now has its own references to the objects that are not affected if a variable in the other module is reassigned.

To solve your problem, assign some default value to h_out at global scope so that other module's don't get errors if they reference it before your function completes. And access the variable through the module to get the shared value instead of doing wildcard imports.

somemodule.py

h_out = None

def LogLikeDeep(B, r):
    global h_out       #IMPORTANT PART
    h_out = h[0]

usage

>>> import somemodule
>>> somemodule.h_out
>>> print(repr(somemodule.h_out))
None
>>> somemodule.LogLikeDeep('foo', 'bar')
>>> print(repr(somemodule.h_out))
'foo'
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • global h_out h_out = None def LogLike(B, r): global h_out h_out = h[0] (...) – SW7 May 12 '17 at 17:48
  • Thank you, I implemented this but when I call hngoption.h_out it returns empty rather than a value. Code: global h_out h_out = None def LogLike(B, r): global h_out h_out = h[0] (...) – SW7 May 12 '17 at 17:54
  • ...and the function has already been called? How about updating your question with a working example and then we can see what is going on. – tdelaney May 12 '17 at 18:00
  • Thank you for your reply, I updated my post, please find a richer excerpt of the code above (full code is too long to post and requires data). Thank you for your hep – SW7 May 12 '17 at 18:22
  • Is there anything else I should add to make it possible to spot the error? Thanks for your help! – SW7 May 12 '17 at 20:43
  • Your code doesn't show enough of what you are doing. Your first anonymous script defines an `h_out` then calls `hmgoption.params(..)` ... which calls `LogLike` (what module is that in?). Then the problematic code that reads `h_out`... where is it? You want the `h_out` in whatever module `LogLike` lives in. – tdelaney May 12 '17 at 20:59