Python Forum

Full Version: Please help me understand how to use global variables
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I'm new to Python as of 1 week ago and I'm trying to write a simple stock market backtester. In my program, I want to change a global variable called 'prev_entry_price' within a function I've defined and saved in a .py file within my project. But the variable doesn't change outside the function, and I don't understand why.

# -----------------
# Here is my code:
# -----------------

prev_entry_price = 0
prev_exit_price = 0

for row in range(2, 5):
    # for row in range(2, sheet.max_row + 1):
    sym_date_cell = sheet.cell(row, 1)
    sym_open_cell = sheet.cell(row, 2)
    sym_high_cell = sheet.cell(row, 3)
    sym_low_cell = sheet.cell(row, 4)
    sym_close_cell = sheet.cell(row, 5)
    sym_volume_cell = sheet.cell(row, 7)
    entry_price_cell = sheet.cell(row, 12)
    exit_price_cell = sheet.cell(row, 13)

    setup_eoddata(row, sym_open_cell, entry_price_cell, prev_entry_price, exit_price_cell, prev_exit_price)

print(f"Row ", row, prev_entry_price, entry_price_cell.value, exit_price_cell.value)


def setup_eoddata(row, sym_open_cell, entry_price_cell, exit_price_cell, prev_exit_price):
    if row == 2:
        global prev_entry_price
        entry_price = sym_open_cell.value
        entry_price_cell.value = entry_price
        prev_entry_price = entry_price
        exit_price = 0
        exit_price_cell.value = exit_price
        prev_exit_price = exit_price

        return prev_entry_price, prev_exit_price
# --------------------------
# My input looks like this:
# --------------------------

1/2/2019	46.94	47.22	46.56	46.93	45.83	11,603,700
1/3/2019	46.82	47.37	46.53	46.64	45.55	14,714,400
1/4/2019	46.75	47.57	46.64	47.57	46.45	13,013,700
1/7/2019	47.57	47.75	46.90	46.95	45.85	13,135,500
# --------------------------
# My output looks like this:
# --------------------------

Output:
Row 2 0 46.939999 0 Row 3 0 None None Row 4 0 None None
Process finished with exit code 0

The third column on the third row should contain '46.939999' but instead, it always comes back as '0'. When I use the debugger, it shows the modified value within the function, as expected. It even shows the modified value in both my calling argument, and called parameter. But still, I get '0' when I print. I've read and tried everything I could find on the Internet about how to use global variables to do this, and I can't get it to work. One other thing, the parameter on my function is grayed out, and when I hover my cursor over it, I see "Parameter 'prev_entry_price' value is not used." Does this matter?

Any help I receive would be greatly appreciated.
First of all, the correct way to use global variables is to not use global variables. Use return statements and assignments:

def foo():
    x = 801
    return x

y = foo()
Second, you function only does anything if row is 2, because of the conditional on line 21. The return statement for the function is part of that conditional, so if row != 2, the default return value of None is returned, which is why your output is full of None's.
Thank you for your response, ichabod801. I understand about the conditional 'If' statement. That was an oversight on my part. I added an 'elif' and 'else', then I moved the return statement to the end of the function and I still get the same thing:


# -----------------
# Here is my code:
# -----------------
prev_entry_price = 0
prev_exit_price = 0

for row in range(2, 5):
    # for row in range(2, sheet.max_row + 1):
    sym_date_cell = sheet.cell(row, 1)
    sym_open_cell = sheet.cell(row, 2)
    sym_high_cell = sheet.cell(row, 3)
    sym_low_cell = sheet.cell(row, 4)
    sym_close_cell = sheet.cell(row, 5)
    sym_volume_cell = sheet.cell(row, 7)
    entry_price_cell = sheet.cell(row, 12)
    exit_price_cell = sheet.cell(row, 13)

    setup_eoddata(row, sym_open_cell, entry_price_cell, prev_entry_price, exit_price_cell, prev_exit_price)

print(f"Row ", row, prev_entry_price, entry_price_cell.value, exit_price_cell.value)


def setup_eoddata(row, sym_open_cell, entry_price_cell, exit_price_cell, prev_exit_price):
    if row == 2:
        global prev_entry_price
        entry_price = sym_open_cell.value
        entry_price_cell.value = entry_price
        prev_entry_price = entry_price
        exit_price = 0
        exit_price_cell.value = exit_price
        prev_exit_price = exit_price

    elif prev_exit_price == 0:
        entry_price_cell.value = prev_entry_price
        exit_price_cell.value = prev_exit_price
    else:
	    Print("Logic Error!")

    return prev_entry_price, prev_exit_price
# --------------------------
# My output looks like this:
# --------------------------
Output:
Row 2 0 46.939999 0 Row 3 0 0 0 Row 4 0 0 0 Process finished with exit code 0
# --------------------------------
# My output should look like this:
# --------------------------------
Output:
Row 2 0 46.939999 0 Row 3 46.939999 46.939999 0 Row 4 46.939999 46.939999 0 Process finished with exit code 0
The first and second columns on the third and fourth rows should contain '46.939999' but instead it always comes back as '0'. When I use the debugger, it shows the modified value within the function, as expected. It even shows the modified value in both my calling argument, and called parameter. But still, I get '0' when I print.

Any help I receive would be greatly appreciated.
And that's a great example of why not to use global. Your global statement is still in the conditional, so the variable is only global if row is 2.

Here's how to fix it. First, delete line 22. Then change line 15 to:

prev_entry_price, prev_exit_price = setup_eoddata(row, sym_open_cell, entry_price_cell, prev_entry_price, exit_price_cell, prev_exit_price)
Thanks again for responding ichabod801. And thank you for doctoring my post. I've read the instructions in the link you sent me and I'll do it properly in the future.

Meanwhile, your recommendations fixed my code alright. Thank you very much! I'm getting exactly what I want now. The reason I was trying to use a global is that I need all 'prev_' values to persist through the processing of the next record in the row.

If I understand how to use the 'return' statement correctly as you've shown it, I don't need a global because the function values are returned to the calling statement after each iteration, thus accomplishing the same thing.

Is my understanding correct?
Well, I don't understand line 17. Your output makes it seem that line 17 is printing each time through the loop. But in what you've posted, it's not indented under the loop, so it should only be printing once.

If that is a typo in what you posted, and it actually is indented under the loop, then yes: the function is returning the value each time through the loop, giving you what you need.
Yes, that's a typo. It prints each time through the loop. I don't know if I can edit that code block to correct the mistake for future readers of this thread. It's only there for debugging purposes and will be removed in the final program. Thanks again.