Reassigning variable in Python

Question:

In Python, I have an expensive function a(x) which is currently evaluated multiple times within another function. At the start of that function, I want to evaluate a(x) once, and reassign the variable name a locally to that value. But I keep getting an Unbound Local Error.

As a MWE:

def a(x):
    return x+1

def main(x):
    a = a(x)
    return a**2

main(3)

#---------------------------------------------------------------------------
#UnboundLocalError                         Traceback (most recent call last)
#Input In [62], in <cell line: 8>()
#      5     a = a(x)
#      6     return a**2
#----> 8 main(3)
#
#Input In [62], in main(x)
#      4 def main(x):
#----> 5     a = a(x)
#      6     return a**2

#UnboundLocalError: local variable 'a' referenced before assignment

Obviously, a workaround is to use a line like b = a(x) instead.

But why is this happening? And how can I reassign the variable name a?

Asked By: David

||

Answers:

The error is occurring because you have already named ‘a’ as a function that you can’t assign as a variable again instead of

a = a(x)

you can name it some other variable like ‘b’ like this

def main(x):
    b = a(x)
    return b**2
Answered By: Vatsal

I would disagree with Vatsal’s previous answer. The error happens because the interpreter thinks that you’re trying to call the same a that you are defining, ie the a before the equals sign. Though you would probably encounter Vatsal’s error later, as in python, functions are assignable to variables.

Answered By: Markus Albinsson

The error happens because in this line:

    a = a(x)

you are redefining a to be a local variable. This occurs for all uses for a within that scope, including the right hand side of the expression. a doesn’t start off as a global and then become a local at some point during the function’s execution at runtime; if there is an assignment to a anywhere in the function, then a is now a local everywhere in that function.

That means that when that line is actually executed, it’s attempting to call the local variable a before anything has been assigned to it.

Here’s a simpler demonstration of the same effect, where we aren’t changing the type of a, and we aren’t referencing it on the same line where we’re assigning to it:

>>> a = 42
>>> def foo():
...     print(a)  # should be 42, right?
...     if False:
...         a = 42  # should be a no-op, right?
...
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'a' referenced before assignment

In this case, the rebinding of a happens after it’s used, and it happens in a block that will never even actually be executed when the function is called — but it doesn’t matter, because at the time the function is defined, the existence of that assignment makes a a local variable.

You can actually see this by inspecting foo itself, without calling it:

>>> foo.__code__.co_varnames
('a',)

Compare with an implementation that doesn’t make a into a local:

>>> def foo():
...     print(a)
...
>>> foo()
42
>>> foo.__code__.co_varnames
()
Answered By: Samwise

Try declaring a as global variable:

def a(x):
    return x+1

def main(x):
    global a  # <<<<<<<< only this line need to be added.
    a = a(x)  # Now a is first called (right side) and then reassigned
    return a**2

print(main(3))

Now it works!

Output:

16

If you check what is a now:

print(a)

Output:

4

So global a has changed. Its no more a function and it cannot be called now:

print(a(3))

Output:

TypeError: 'int' object is not callable
Answered By: rnso
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.