Unboundlocalerror with Nested Function Scopes

UnboundLocalError with nested function scopes

If you're using Python 3, you can use the nonlocal statement to enable rebinding of a nonlocal name:

def outer():
ctr = 0

def inner():
nonlocal ctr
ctr += 1

inner()

If you're using Python 2, which doesn't have nonlocal, you need to perform your incrementing without barename rebinding (by keeping the counter as an item or attribute of some barename, not as a barename itself). For example:

...
ctr = [0]

def inner():
ctr[0] += 1
...

and of course use ctr[0] wherever you're using bare ctr now elsewhere.

Nested function definitions and scope (UnboundLocalError)

Python needs first to detect what variables are local, and which variable are fetched from an outer scope. In order to do that it looks for assignments, like:

def foo1(x=5):
def bar():
if x == 5:
x = 6 # an assignment, so local variable
print(x)
bar()

The point is, that the assignment can happen anywhere. For instance on the last line. Nevertheless, from the moment there is an assignment somewhere x is local. So in your first code fragment, x is a local variable. But you fetch it before it is assigned (bounded), so Python will error on it.

In python-3.x you can use the nonlocal keyword to access x from an outer scope:

def foo1(x=5):
def bar():
nonlocal x
if x == 5:
x = 6
print(x)
bar()

For python-2.x, you can for instance assign the variable to the function, like:

def foo1(x=5):
def bar():
if bar.x == 5:
bar.x = 6
print(bar.x)
bar.x = x
bar()

Note however that the two are not equivalent. Since in the former if you alter x, it will be alter the x in the foo1 scope as well. In the latter example you only modify bar.x. Of course if these are mutable objects, you alter the same object.

Nested Function Scope

I don't think the other answers narrate the entire story, so here's my 2 cents.

The scope does not differ between types. That's not what's happening here.
Rebinding a name, regardless of what that name refers to, will always cause an unbound local error to occur.

Some types in Python are mutable (once created, a value can be changed), and list is one of them. Some are immutable, and changing a value of these types requires creating a new object.

So, with the first example,

def foo():
a = 0
def bar():
a += 1
bar()
foo()

This doesn't work because you effectively have an assignment taking place here, a = a + 1. You can use non-local to make the above work, that being besides the point.

Doing the same thing with a list:

def foo():
a = []
def bar():
a.append(1)
bar()
foo()

This does indeed work. There is no assignment taking place here.

You can't re-bind the name to a different object, but if the object is mutable, you can modify its contents.

Now, there's 2 more cases you should be aware of.

def foo():
a = []
c = []
def bar():
a = c + [1]

bar()
print(a)
print(c)
foo()

This will work, however you should note that the a inside bar() now is local to bar, and the print() statement should reflect that.

But here's a gotcha

def foo():
a = []
def bar():
a = a + [1] #or even a += [1], doesn't matter

bar()
print(a)
foo()

This won't work! (And it's important you contrast this snippet with the first snippet, because that addresses why this has nothing to do with scopes. Take a minute to read it again.)

So this doesn't work and it's important to understand it.

If there is an assignment to a variable inside a function, that variable is considered local.

Now, in the last case, when we did a = c + 1, it was more like a_local = c_nonlocal + 1.

In this case, a = a + 1 is a_local = a_local + 1 and hence, that will indeed cause an error.

This is why, Rebinding a name, regardless of what that name refers to, will always cause an unbound local error to occur.
In the case earlier(The third snippet), it wasn't rebinding it - it was creating a local variable.
In the latter case(The fourth snippet), it was infact rebinding and hence the error.

Python 3 parameter closed upon by inner/nested method falls out of scope and triggers UnboundLocalError

The problem is that you reference uuidString in the call to self.getMethodThatProvidesFullFilePathNameForPricesCsvFromUUIDAndTickerName before you assign to it. The assignment makes it local to the scope of the innermost function and therefore, it is unassigned when you reference it.

A full description of the scoping rules is provided by: https://stackoverflow.com/a/292502/7517724

This simpler example reproduces your error to make the problem more clear:

class aclass():

def outer(self, uuidString):
def inner():
print(uuidString)
uuidString = 'new value'
return uuidString
return inner

a = aclass()
func = a.outer('a uuid')
val = func()
print(val)

The assignment in inner() causes the uuidString to be local to inner() and therefore it is unassigned when the print(uuidString) is call, which causes Python to raise the UnboundLocalError.

You can fix the error by passing the variable in to your function with a default argument. Changing the definition of saveData to pass uuidString as a default argument, as:

def saveData(uuidString=uuidString):

will make it work as you expect.

Python nested functions variable scoping

When I run your code I get this error:

UnboundLocalError: local variable '_total' referenced before assignment

This problem is caused by this line:

_total += PRICE_RANGES[key][0]

The documentation about Scopes and Namespaces says this:

A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects.

So since the line is effectively saying:

_total = _total + PRICE_RANGES[key][0]

it creates _total in the namespace of recurse(). Since _total is then new and unassigned you can't use it in the addition.

UnboundLocalError in recursive call of nested function

Because you're assigning results inside of a nested function, Python assumes you're using a locally scoped variable and throws up at line 35 even though it's a valid name in a higher scope. If you were only reading the variable and not writing to it, it will oftentimes work on the higher namespace object. But as soon as an assignment operator appears, you jump to local namespace.

From Python scopes/namespaces:

A special quirk of Python is that – if no global statement is in
effect – assignments to names always go into the innermost scope.
Assignments do not copy data — they just bind names to objects.

To get around this, the easiest is to pass the variable you want use into the function header:

def extend_prefix(w, letters, results):
if w in WORDS: results.add(w)
if w not in PREFIXES: return
for L in letters:
extend_prefix(w + L, letters.replace(L, "", 1), results)

Also the way you wrote the function, you weren't returning a set, so the results = results | result would have blown up with results being None Type.

UnboundLocalError with nested function when modifying parent function argument

The second chunk of code fails because hi is a parameter in the scope of the hello function, yet it is assigned again in the world function

How do I change global variable in nested scope using python?

The swaps variable in your code is not global, it's nonlocal. It was defined in the enclosing function getNumOfSwapsToSort(), not in the global namespace.

Your other function, swap(), has access to this nonlocal variable, but the variable is protected from being edited from the inner function. If you try to edit or overwrite it, it's going to be treated as a new, local variable - hence the UnboundLocalError you're getting.

Try using the nonlocal statement:

nonlocal swaps
swaps += 1

Here's an article with a few simple examples which explain the concept of closure in Python.



Related Topics



Leave a reply



Submit