3

Ran into the following problem. It's probably a simple solution, and has probably been asked here before, but I couldn't find it.

def a():
    liA = []
    def b():
        for i in liA:
            i += 1
        liB = generateList()
        for i in liB:
            i -= 1
        liA = liB

    def generateList():
        return [1,2,3,4]

    b()

a()

UnboundLocalError: local variable 'liA' referenced before assignment

tsorn
  • 3,365
  • 1
  • 29
  • 48

2 Answers2

4

liA variable in b() function is never initialized.

So, you should edit the code in the followed way:

def a():
    liA = []
    def b(liA):
        for i in liA:
            i += 1
        liB = generateList()
        for i in liB:
            i -= 1
        liA = liB

    def generateList():
        return [1,2,3,4]

    b(liA)

a()

Hope I helped you!

Maroun
  • 94,125
  • 30
  • 188
  • 241
vathek
  • 531
  • 2
  • 9
  • Why should this variable be passed and shadowed as a parameter? There is clearly a `liA` variable that has been given a value. – user2864740 Aug 31 '15 at 06:52
  • Simply remove `liA = liB` there's no need to pass anything, `b` already knows what `liA` is but the assignment makes it a local variable. Secondly the assignment `liA = liB` is not going to affect the passed `liA` in any way. – Ashwini Chaudhary Aug 31 '15 at 06:54
  • becouse the liA variable with its given value is not visibile inside b() function. Another solution may be to use a global variable, so decalre liA outside a() and define it global inside every function that use it. – vathek Aug 31 '15 at 06:55
  • @vathek ..but the outer `liA` variable *is* visible (take out the assignment of `liA = liB` and the original code will not throw an error); the issue comes when there is an *assignment* in scope. But *why*? – user2864740 Aug 31 '15 at 06:57
  • liA is a new local variable in b() and no the original one – vathek Aug 31 '15 at 06:58
1

If you look at the whole stack trace you get a much better idea of how the error is happening.

Traceback (most recent call last):
  File "/Users/jwp/Desktop/junk.py3", line 16, in <module>
    a()
  File "/Users/jwp/Desktop/junk.py3", line 14, in a
    b()
  File "/Users/jwp/Desktop/junk.py3", line 4, in b
    for i in liA:
UnboundLocalError: local variable 'liA' referenced before assignment

So the error is being thrown when you call b() because you do not declare liA in the context of b() and then use it in the assignment liA = liB.

The most obvious answer would be to pass liA into b() as an argument. Like this:

def a():
    liA = []
    def b(inlist):
        liA = inlist
        for i in liA:
            i += 1
        liB = generateList()
        for i in liB:
            i -= 1
        liA = liB

    def generateList():
        return [1,2,3,4]

    b(liA)

a()

Does that meet your needs?

jwpfox
  • 5,124
  • 11
  • 45
  • 42
  • Then [how does this work](https://repl.it/BE9O), where `var_in_a` is assigned in the parent (`a`) scope only? (Or maybe my question should be: 'how to rebind a variable in the containing scope'?) – user2864740 Aug 31 '15 at 06:54
  • @user2864740 Read [this answer](http://stackoverflow.com/a/8934902/216074). If you don’t assign to a variable within a scope, that variable isn’t locally declared, so the name lookup will check outer scopes for the name. That’s why you can read a variable from the outer scope just fine, but everything breaks when you start assigning to it. Then, it becomes a new variable. – poke Aug 31 '15 at 06:58