Reputation: 8376
At this code snippet:
def taylorVazquez(fx,a,b,n,puntos):
puntosX = linspace(a,b,num=puntos)
aproxY = []
puntosY = []
def toFloat():
puntosX = [float(x) for x in puntosX]
aproxY = [float(y) for y in aproxY]
puntosY = [float(y) for y in puntosY]
I'm getting the error message:
UnboundLocalError: local variable 'puntosX' referenced before assignment
And so I know same would happen to the other two variables. What can I do it's the outer taylorVazquez
's variables the ones I manipulate at inner function, in other words, I want the assignments to work for the outer scope too
Upvotes: 3
Views: 143
Reputation: 11601
Whenever you assign a value to a variable in a given scope, the variable is assumed to be local to that scope. Depending on which Python you are using, you will either need to use nonlocal (Python 3) or pass the values in using parameters (Python 2).
Here is Python 2:
def toFloat(puntosX, aproxY, puntosY): # now the names of the enclosing function can be passed to the toFloat function
puntosX = [float(x) for x in puntosX]
aproxY = [float(y) for y in aproxY]
puntosY = [float(y) for y in puntosY]
In Python 3:
def toFloat():
nonlocal puntosX, aproxY, puntosY # the names now refer to the enclosing scope rather than the local scope
puntosX = [float(x) for x in puntosX]
aproxY = [float(y) for y in aproxY]
puntosY = [float(y) for y in puntosY]
global
will NOT work in this situation, since you are referencing the names of an enclosing function.
One more thing, you MAY be trying to assign new values to the names in the enclosing scope. Your present tactic will not work, since you are assigning new objects to these names within the innermost function. (List comprehensions create new lists.) If you need to keep the new values, you will need to (for example) return these values to the enclosing scope and reassign your original names to the new values. For example, in Python 2:
def taylorVazquez(fx,a,b,n,puntos):
puntosX = linspace(a,b,num=puntos)
aproxY = []
puntosY = []
def toFloat(puntosX, aproxY, puntosY): # now the names of the enclosing function can be passed to the toFloat function
puntosX = [float(x) for x in puntosX]
aproxY = [float(y) for y in aproxY]
puntosY = [float(y) for y in puntosY]
return puntosX, aproxY, puntosY
puntosX, aproxY, puntosY = toFloat(puntosX, aproxY, puntosY) # now you can reassign these names to the new values
Unlike global
, you cannot assign new values to these names and have them hold for the enclosing scope.
Upvotes: 2
Reputation: 104802
If you assign to a variable in a Python function, the interpreter assumes that it is a local variable. All other uses of that variable are also assumed to be local, even ones that come before the assignment. This is why you get an exception about local variable 'puntosX' referenced before assignment
.
There are a few possible solutions.
One is to declare the variable to be global
(or in Python 3, nonlocal
if its a local variable in an enclosing function).
def taylorVazquez(fx,a,b,n,puntos):
puntosX = linspace(a,b,num=puntos)
aproxY = []
puntosY = []
def toFloat():
nonlocal puntosX, aproxY, puntosY # this fixes the UnboundLocalError
puntosX = [float(x) for x in puntosX]
aproxY = [float(y) for y in aproxY]
puntosY = [float(y) for y in puntosY]
Another option is to mutate the variable in place, rather than reassigning it. For instance, you can use list.append
and list.__setitem__
on a list without ever making a local reference to it.
def toFloat():
for i, v in enumerate(puntosX):
puntosX[i] = float(v) # this calls puntosX.__setitem__, mutating it in place
# etc...
A last option is to unnest your functions and pass arguments and return values, rather than relying on the nested namespaces to make your values available. For instance:
def toFloat(lst):
return [float(v) for v in lst]
# then later
puntosX = toFloat(puntosX)
Upvotes: 2
Reputation: 21934
You can access the variable just fine, the issue here is that in Python2 there's no way to reassign the variable. There's a PEP in for fixing this issue (PEP-227).
It was in fact addressed in Python 3, and you could label your variables as nonlocal
, but that's not a huge comfort if you're still using Python 2.
You can work around it by doing something like this:
def f1():
x = [1]
def f2():
x[0] = 2
f2()
print x[0]
f1()
There are also a number of other potential workarounds, but most of them will result in unexpected behavior.
Upvotes: 1