1

Consider the following code:

def g():
    a = {}
    b = 0
    def f():
        a[0] = b
    f()
    print(a)
    return a
a = g()
print(a)

It gives the following output when executed:

{0: 0}
{0: 0}

But if I try to update b in f() as in

def g():
    a = {}
    b = 0
    def f():
        a[0] = b
        b+=1
    f()
    print(a)
    return a
a = g()
print(a)

It throws the following error:

UnboundLocalError: local variable 'b' referenced before assignment

Is this expected? I need to update b inside f(). Is that impossible?

Raghuram Vadapalli
  • 1,150
  • 2
  • 12
  • 27
  • https://stackoverflow.com/questions/929777/why-does-assigning-to-my-global-variables-not-work-in-python – DhruvPathak Sep 09 '17 at 19:32
  • Rather than trying to solve the apparent problem, I would suggest that you change your strategy so that you don't need to mutate non-local variables. Wherever possible, prefer pure functions. And if you do need to mutate, do it explicitly (passing the variables as function args) rather than indirectly. – FMc Sep 09 '17 at 19:38
  • Thanks @FMc, I will keep that in mind in future. – Raghuram Vadapalli Sep 09 '17 at 19:39

2 Answers2

2

Explicitly pass a and b to your function.

def g():
    a = {}
    b = 0
    def f(a, b):
        a[0] = b
        b += 1
        return b
    b = f(a, b)
    return a
Alexander
  • 96,739
  • 27
  • 183
  • 184
1

You need to use the nonlocal keyword:

def g():
    a = {}
    b = 0
    def f():
        nonlocal b
        a[0] = b
        b+=1
    f()
    print(a)
    return a
a = g()
print(a)

This is because b += 1 is equal to b = b + 1, so you're assigning b inside of the function f(). Even though it's later in the code, this will make it a local variable for the whole f() function, and thus a[0] = b will refer to the local b which isn't defined yet. Using nonlocal tells the interpreter that there's already a variable b and it should be used in the function, instead of creating a new local variable.

Markus Meskanen
  • 17,674
  • 15
  • 70
  • 114