Python Forum

Full Version: unbounded variable
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
hi
in code:
'''
ref:https://www.bhavaniravi.com/python/advanced-python/unbound-variables-in-python
'''

def take_sum(a, b, c):
    return a+b+c

def main1():
    print(take_sum)    # output is as :<function take_sum at 0x1031c84c0>
    if "take_sum" not in  globals():
        print("take_sum is not in globals()")
    else:
        print("take_sum is in globals()")
    print(globals())
    print('-'*30)    


def main():
    if "take_sum" not in globals():
        take_sum = lambda x,y,z: x+y+z
    print(take_sum)
    

main1()
main()
output has the below error:
Error:
Traceback (most recent call last): File "D:\akb_python\akb_py_projects\unbounded_variable.py", line 25, in <module> main() File "D:\akb_python\akb_py_projects\unbounded_variable.py", line 21, in main print(take_sum) UnboundLocalError: local variable 'take_sum' referenced before assignment
'''
I read the explanation given in the address in the docstring, but I did not understand. (I selected the thread subject from there).
what is the problem?plz, explain
thanks
Variables are "created" when Python code is parsed, not when it is executed. Before main() was ever called, the code for main "defined" a local vairable named "take_sum". You can see that if you look at the generated bytecode. Below I simplify the function to focus on the variable.
import dis


def main():
    if "take_sum" not in globals():
        take_sum = 1
    print(take_sum)


print(dis.dis(main))
Output:
16 PRECALL 0 20 CALL 0 30 CONTAINS_OP 1 32 POP_JUMP_FORWARD_IF_FALSE 2 (to 38) 6 34 LOAD_CONST 2 (1) 36 STORE_FAST 0 (take_sum) 7 >> 38 LOAD_GLOBAL 3 (NULL + print) 50 LOAD_FAST 0 (take_sum) 52 PRECALL 1 56 CALL 1 66 POP_TOP 68 LOAD_CONST 0 (None) 70 RETURN_VALUE
Even if the comparison in line 5 (of the python code) causes execution to skip the assignment in line 6, main() still has a variable named (take_sum). It is part of the function's code.

main() creates (take_sum) because line 6 does an assignment to the variable. (take_sum) is a local variable because main() does not declare it as global.
Notice how the code changes if we declare take_sum as global.
import dis


def main():
    global take_sum
    if "take_sum" not in globals():
        take_sum = 1
    print(take_sum)


print(dis.dis(main))
Output:
4 0 RESUME 0 6 2 LOAD_CONST 1 ('take_sum') 4 LOAD_GLOBAL 1 (NULL + globals) 16 PRECALL 0 20 CALL 0 30 CONTAINS_OP 1 32 POP_JUMP_FORWARD_IF_FALSE 2 (to 38) 7 34 LOAD_CONST 2 (1) 36 STORE_GLOBAL 1 (take_sum) 8 >> 38 LOAD_GLOBAL 5 (NULL + print) 50 LOAD_GLOBAL 2 (take_sum) 62 PRECALL 1 66 CALL 1 76 POP_TOP 78 LOAD_CONST 0 (None) 80 RETURN_VALUE
Now main() uses STORE_GLOBAL and LOAD_GLOBAL when referencing (take_sum).

To fix your code, you could modify main() to always assign something to take_sum:
def take_sum(a, b, c):
    return a+b+c
 
def main():
    if "take_sum" in globals():
        take_sum = globals()["take_sum"]
    else:
        take_sum = lambda x,y,z: x+y+z
    print(take_sum)

main()
Or you could declare take_sum as global
def take_sum(a, b, c):
    return a+b+c


def main():
    global take_sum
    if "take_sum" not in globals():
        take_sum = lambda x,y,z: x+y+z
    print(take_sum)
     

main()
hi, thanks
I read your reply, although I am unfamiliar with dis module.so I did not understand the blue sections of your reply.
can I ask you why the error is not created in main1 function (in my Python code)?
thanks again
Quote:I am unfamiliar with dis module.so I did not understand the blue sections of your reply.
You can read all about the python disassembler here:
https://docs.python.org/3/library/dis.html

Quote:why the error is not created in main1 function
There are no assignments in main1, so main1 doesn't make a local variable. This would generate an error
def main1():
    print(take_sum) 
If you didn't have a function named "take_sum" in the global namespace. When accessing variables python first looks local, then enclosed, global and finally built-in.