0

I am confused about these code:

def a():
    count1=[0]
    count2=0
    def b():
        count1[0]=count1[0]+1
        count2=count2+1
        print count1,count2
    b()

count1 is announced as a list, it works well, while count2 in b() will cause referenced before assignment error. Why?

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
Ziu
  • 649
  • 1
  • 8
  • 20

4 Answers4

4

In your code count1 is the reference of the list and with count1[0] you try to access the 0th index of the count1 list. Hence, when you do:

count1[0] = count1[0]+1

you are accessing the same count1 object defined outside the b() function.

But that's not the case with count2. When you do:

 count2 = count2 + 1

You are trying to create a new count2 object and in this case b() won't read the value of count2 from the outer scope. In order to access the count2 from the outer scope, you may use nonlocal keyword (available since Python 3.x). Hence, your code should be as:

 # For Python 3.x

 def a():
    count2=0
    def b():
        nonlocal count2
        # ^ used here
        count2 = count2+1
    b()

But since you are using Python 2.x and nonlocal is not available in it, you may do a workaround via using dict to store count2 variable as:

 # Workaround for Python 2.x

 def a():
    nonlocal_dict = {   # `dict` to store nonlocal variables
        'count2': 0
    } 
    def b():
        nonlocal_dict['count2'] = nonlocal_dict['count2']+1
        # ^ this `dict` will be available here
    b()

Please also take a look at:

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
2

First, you can access but not modify a variable which is beyond current scope. If you really want to do this, you have to use key word nonlocal.

Second, count1 is actually a reference of an instance of list object, so if you don't change what it refer, it is not a modification direct to this variable.

Third, count2 is a real value, and changing it's value means a modification direct to this variable.

You can test this by replace count1[0]=count[0]+1 with count1=list(). It will cause exception too.

Sraw
  • 18,892
  • 11
  • 54
  • 87
1

Because b assigns to count2, which implicitly creates count2 as a local variable in b, which in turn makes all references to count2 in b refer to this local variable. So at this line:

count2 = count2 + 1
#        ^^^^^^

You're trying to read from a variable that hasn't been initialized yet.

count1 is different because b only reads from count1; it never assigns to it:

count1[0] = ...

This reads from count1 to get the contained list, then modifies the first element.

melpomene
  • 84,125
  • 8
  • 85
  • 148
0

you need to use nonlocal keyword because in python variable follow LEGB rules means it is first look for local, enclosing, global , Built-in scope. Here you are accessing enclosing variable so you should use nonlocal in front of variable.

def a():
        count1=[0]
        count2=0
        def b():
            nonlocal count2
            count1[0]=count1[0]+1
            count2=count2+1
            print (count1,count2)
        b()

    a()
vishalsh
  • 11
  • 1