0

This code:

my_num = 0

def my_func():
  my_num = my_num + 1
my_func()

causes the following error:

Traceback (most recent call last): File "main.py", line 5, in my_func() File "main.py", line 4, in my_func my_num = my_num + 1 UnboundLocalError: local variable 'my_num' referenced before assignment

Why does the interpreter not read the expression as:

my_num = 0 + 1
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • Because you didn't say inside the function that you wanted to use the global one. Research the error message. – jonrsharpe May 02 '20 at 13:38
  • If I wrote: `x = my_num + 1` it would work, however. – programmer1 May 02 '20 at 13:43
  • Yes, because then there's no ambiguity - x is only local, my_num is only global – jonrsharpe May 02 '20 at 13:44
  • Where does the ambiguity arise? I don't understand, I would think that the variable defaults to the parent if it is not assigned within the local scope. – programmer1 May 02 '20 at 13:46
  • 1
    https://stackoverflow.com/search?q=%5Bpython%5D+unboundlocalerror – jonrsharpe May 02 '20 at 13:48
  • *Why does the interpreter not read the expression* - that is because the variable is declared local by the **compiler**. So when the interpreter tries to evaluate it in the RHS, it is not yet initialized (in its local scope). Read more in the [official docs](https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value) – Tomerikoo May 02 '20 at 15:51

2 Answers2

0

Because you can read the values of global variables without doing anything special, but not write them unless you use the global keyword.

In this line my_num = my_num + 1 you are trying to read and write a global variable. Since you didn't specify that my_num is a global variable with global my_num in your function, the interpreter sees the left hand side of the assignment as a new local variable, and thus the right hand side variable doesn't make any sense.

Any value that is assigned to in a function is treated as a local variable unless there is an explicit global statement. From the docs:

Assignment of an object to a single target is recursively defined as follows.

  • If the target is an identifier (name):

    • If the name does not occur in a global or nonlocal statement in the current code block: the name is bound to the object in the current local namespace.
ruohola
  • 21,987
  • 6
  • 62
  • 97
  • Does the interpreter read the left hand side first? If it read the right hand side first then it would use the global variable and then recognise that a new variable is being declared. – programmer1 May 02 '20 at 13:49
  • @rcwhiteley It evaluates the right hand side first. – ruohola May 02 '20 at 13:52
  • So surely the interpreter uses the global value of `my_num` on the right hand side and then creates a new local variable on the left hand side. I am trying to understand why this causes an error. I know I could avoid this by using the keyword global, but trying to understand how the interpreter works. – programmer1 May 02 '20 at 13:58
  • @rcwhiteley Any value that is assigned to in a function is treated as a local variable unless there is an explicit `global` statement. – ruohola May 02 '20 at 14:18
  • @rcwhiteley Evaluation order is different than the parsing order. – ruohola May 02 '20 at 14:23
  • 1
    @rcwhiteley Evaluation order is RHS then LHS. The problem is that the **compiler** defines the variable as local. So by the time the interpreter tries to evaluate the variable, it is not yet defined in the **local scope** and hence the error – Tomerikoo May 02 '20 at 15:54
  • Thank you, @Tomerikoo. Your explanation is what makes sense to me, I did not know that Python is compiled and then interpreted! I thought it was just an 'interpreted' language. That makes sense that the variable has been defined as local, so it makes sense why the interpreter does not assign the global variable to it. – programmer1 May 02 '20 at 17:55
  • @rcwhiteley glad to help. I also commented on the question with a link from the docs that might help clear things up – Tomerikoo May 03 '20 at 07:32
-1

You need to declare my_num as global:

    def my_func():
      global my_num
      my_num = my_num + 1
piet
  • 116
  • 1
  • 1
  • 6