0

I am curious why the following code generates error:

def test_method():
    main_var = 0
    main_list = list()
    def sub_method():
        print(main_list)
        main_list.append(0)
        print(main_list)
        print(main_var)
        main_var +=1
        print(main_var)
    sub_method()

Error

UnboundLocalError: local variable 'main_var' referenced before assignment

In particular, it does not complain about list, but does complain about variable.

user1700890
  • 7,144
  • 18
  • 87
  • 183
  • Note, the linked duplicate was the first hit when I googled "unbound local error". Please try to see if your question has already been answered before posting a new one. – juanpa.arrivillaga May 29 '19 at 18:55
  • @juanpa.arrivillaga. Do you know it does not happen to list? – user1700890 May 29 '19 at 18:57
  • 1
    Did you read the explanation in the linked duplicate? It has nothing to do with it being a *list*. In one case, the variable `main_var` is assigned to inside `sub_method` (note, this isn't a method, but a normal function). In which case, `main_var` is treated as *local to `sub_method` by default*. no assignment occurs to `main_list` so it isn't automatically local. – juanpa.arrivillaga May 29 '19 at 19:01
  • 1
    List object is mutable, so can be changed in any scope. comment #main_var +=1, it works fine. – Masoud May 29 '19 at 19:07
  • @Masoud, Thank you! Does it mean that variable is not mutable? – user1700890 May 29 '19 at 19:08
  • it means that int is immutable. – Masoud May 29 '19 at 19:10
  • 1
    @Masoud **no** mutability/immutabilty is **irrelevant**. The *type* of the variable has no bearing here, **assignment to a variable always makes it local**. `main_list += ['foo']` *would fail in the exact same way for the exact same reason*. Immutable objects simply lack mutator methods. – juanpa.arrivillaga May 29 '19 at 19:12
  • @juanpa.arrivillaga: When you call a mutable object in any scope, even as a function argument, no new object is created. it means that all variables are pointing to the same object. This is why no matter where you mutate a list object. But any mutable object is created and lived in its own scope. – Masoud May 29 '19 at 19:19
  • @Masoud no, that is absolutely incorrect. *Mutable/immutable* is irrelevant to the semantics. They work exactly the same way. Immutable objects *simply lack mutator methods*. Again **`main_list += ['foo']`** would give you **the exact same error for the exact same reason**, the mutability o fthe objects that the variables happen to be referring to is irrelevant to this. – juanpa.arrivillaga May 29 '19 at 19:21
  • try this: main_var[:] = main_var + [1].. check the error... Not the same error.... because here the main object main_var is tried to be mutated... not a new object – Masoud May 29 '19 at 19:35
  • @Masoud **yes** because in that case you are using a hidden mutator method, `main_var.__setitem__`, which doesn't make `main_var` local. But again **the type is irrelevant to the issue above**. If you did `main_var += [1]` it will *fail the same way for the same reason*. `x += y` is equivalent to `x = x.__iadd__(y)`, whereas `x[:] = y` is equivalent to `x.__setitem__(slice(None, None), y)` which doesn't contain a hidden assignment (which it looks like it does). Again *mutability is irrelevant to the problem the OP is encountering* The problem occurs because of the *assignment* not the *type* – juanpa.arrivillaga May 29 '19 at 19:39
  • @juanpa.arrivillaga, so assignment would trigger Python to consider variable local, while `append` would not. What are other operations that would not trigger Python to consider variable local? – user1700890 May 29 '19 at 20:02
  • 1
    @user1700890 only assignment does this. `.append` has no special status, it is merely accessing an attribute on an object then calling it. Note, assignment marks a variable as local *at compile time*. – juanpa.arrivillaga May 29 '19 at 20:03

0 Answers0