0

I encountered an interesting error. When defining a list outside the scope of a function, like below, it causes an error: UnboundLocalError: local variable 'a' referenced before assignment

def main():
    a = []
    
    def sub():
        a += ["hello"]
        return a 
    sub()
main()

However, with the same logic, if used a.append no error is raised

def main():
    a = []
    
    def sub():
        a.append("hello")
        return a 
    sub()
main()

Is there any reason for this?

Thanks

jinjineos
  • 157
  • 9
  • 1
    Does this answer your question? [Why can't Python increment variable in closure?](https://stackoverflow.com/questions/21959985/why-cant-python-increment-variable-in-closure) – PieCot Jan 23 '21 at 16:48

2 Answers2

1

You have to use the nonlocal keyword in this case.
nonlocal documentation

def main():
    a = []
    
    def sub():
        nonlocal a
        a += ["hello"]
        return a 
    sub()
main()
Lcj
  • 371
  • 3
  • 10
1

If you look at the python bytecode that is generated. For this portion.

from dis import dis

def main():
    a = []
    
    def sub():
        a.append(['hello'])
        return a 
    print(dis(sub))
    sub()
main()

OUTPUT

  8           0 LOAD_DEREF               0 (a)
              2 LOAD_METHOD              0 (append)
              4 LOAD_CONST               1 ('hello')
              6 BUILD_LIST               1
              8 CALL_METHOD              1
             10 POP_TOP

 10          12 LOAD_DEREF               0 (a)
             14 RETURN_VALUE

You can see we are loading a reference of a the list to the function using LOAD_DEREF. While on

from dis import dis

def main():
    a = []
    
    def sub():
        a += ["hello"]
        return a 
    print(dis(sub))
    sub()
main()

OUTPUT

  9           0 LOAD_FAST                0 (a)
              2 LOAD_CONST               1 ('hello')
              4 BUILD_LIST               1
              6 INPLACE_ADD
              8 STORE_FAST               0 (a)

 10          10 LOAD_FAST                0 (a)
             12 RETURN_VALUE

we try to load a local variable a into memory and we use a LOAD_FAST instruction. That is why there is an error. If you use nonlocal variable. You would load the variable with LOAD_DEREF.

Also read this answer for why we do so.

Albin Paul
  • 3,330
  • 2
  • 14
  • 30