Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
unbounded variable
#1
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
Reply
#2
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()
akbarza likes this post
Reply
#3
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
Reply
#4
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.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020