sumar - tipos de variables en python
¿Cómo cambiar una variable después de que ya está definida? (6)
Estoy tratando de sumar o restar de una variable definida, pero no puedo entender cómo sobrescribir el valor anterior con el nuevo.
a = 15
def test():
a = a +10
print ( a )
test()
Mensaje de error:
Traceback (most recent call last):
File "test.py", line 7, in <module>
test()
File "test.py", line 4, in test
a = a +10
UnboundLocalError: local variable ''a'' referenced before assignment
El alcance de la variable es local para el bloque a menos que se defina explícitamente usando la palabra clave
global
.
Hay otra forma de acceder a la variable global local a una función utilizando la función global
a = 15
def test():
a = globals()[''a'']
a += 10
print ( a )
test()
El ejemplo anterior imprimirá
25
mientras mantiene intacto el valor global, es decir,
15
.
El error que obtiene cuando intenta ejecutar su código es:
UnboundLocalError: local variable ''a'' referenced before assignment
... lo cual, a primera vista, parece extraño: después de todo, la
primera
declaración en el código anterior (
a = 15
) es una asignación.
Entonces, ¿qué está pasando?
En realidad, están sucediendo dos cosas distintas, y ninguna de ellas es obvia a menos que ya sepas sobre ellas.
En primer lugar, en realidad tienes dos variables diferentes:
-
La
a
en su primera línea es una variable global (llamada así porque existe en el ámbito global, fuera de cualquier definición de función). -
La
a
en las otras líneas es una variable local, lo que significa que solo existe dentro de su funcióntest()
.
Estas dos variables no están relacionadas entre sí, a pesar de que tienen el mismo nombre.
Una variable es local para una función si hay una instrucción que se le asigna dentro de esa función, por ejemplo, su línea
a = a +10
.
Aun así, el error todavía parece extraño: después de todo, lo primero que hace dentro de
test()
es asignar a
a
, entonces, ¿cómo se puede hacer referencia de antemano?
La respuesta es que, en una declaración de asignación, Python evalúa todo en el lado derecho del signo
=
antes de asignarlo al nombre en el lado izquierdo, por lo que aunque la asignación se
escribe
primero en su código, primero se hace
referencia a un
en ese lado derecho:
a +10
.
Hay dos formas de evitar esto.
El primero es decirle a Python que realmente desea que
a
test()
interna
test()
sea la misma en el ámbito global:
def test():
global a
a = a + 10
print(a)
Esto funcionará, pero es una forma bastante mala de escribir programas. La alteración de las variables globales dentro de las funciones se hace difícil de administrar realmente rápido, porque generalmente tiene muchas funciones, y ninguna de ellas puede estar segura de que otra no esté jugando con la variable global de alguna manera que no esperan.
Una mejor manera es pasar variables como argumentos a funciones, así:
a = 15
def test(x):
x = x + 10
print(x)
test(a)
Tenga en cuenta que el nombre no tiene que ser el mismo: su nueva definición de
test()
solo dice que acepta un valor y luego hace algo con él.
Puede pasar lo que quiera, podría ser
a
número
7
o algo más.
De hecho, su código siempre será más fácil de entender si intenta evitar tener variables con el mismo nombre en diferentes ámbitos.
Si juegas con el código anterior, notarás algo interesante:
>>> a = 15
>>> test(a)
25
>>> a
15
...
a
no ha cambiado!
Esto se debe a que, aunque lo pasó a
test()
y se asignó a
x
, entonces fue
x
que cambió, dejando solo el original.
Si realmente desea cambiar
a
, debe devolver su
x
modificado de la función y luego reasignarlo a
a
en el exterior:
>>> a = 15
>>>
>>> def test(x):
... x = x + 10
... print(x)
... return x
...
>>> a = test(a)
25
>>> a
25
Estás modificando una variable creada en el alcance de la función
test()
.
Si desea que se modifique el outter a, puede hacer lo siguiente:
a = 15
def test():
global a
a = a + 1
print(a)
test()
Lo haría de esta manera:
def test(a):
a = a +10
return a
print(test(15))
Tenga en cuenta que en la versión propuesta aquí hay algunas cosas diferentes a las suyas.
Primero, lo que escribí crearía una función que tiene, como entrada, el valor a (en este caso establecido en 15 cuando llamamos a la función -ya definida en la última línea-), luego asigna al objeto un valor a (que era 15) más 10, luego devuelve a (que ha sido modificado y ahora es 25) y, finalmente, imprime una salida gracias a la última línea de código:
print(test(15))
Tenga en cuenta que lo que hizo no fue en realidad una función pura, por así decirlo.
Por lo general, queremos que las funciones obtengan un valor de entrada (o varios) y devuelvan un valor de entrada (o varios).
En su caso, tenía un valor de entrada que estaba realmente vacío y sin valor de salida (ya que no usó
return
).
Además, trató de escribir esta entrada fuera de la función (que, cuando la llamó diciendo
test(a)
el valor
a
no se cargó y le dio el error, es decir, a los ojos de la computadora, estaba "vacío") .
Además, le animo a que se acostumbre a escribir
return
dentro de la función y luego a usar print cuando lo llame (tal como lo escribí en la última línea de codificación:
print(test(15))
) en lugar de usarlo dentro de la función .
Es mejor usar print solo cuando llama a la función y desea ver qué está haciendo realmente la función.
Al menos, esta es la forma en que me mostraron en las lecciones básicas de programación. Esto se puede justificar de la siguiente manera: si está utilizando el retorno dentro de la función, la función le dará un valor que luego puede usarse en otras funciones (es decir, la función retorno es algo con lo que puede trabajar). De lo contrario, solo aparecería un número en la pantalla con una impresión , pero la computadora no podría seguir trabajando con él.
PD: Puedes hacer lo mismo haciendo esto:
def test(a):
a +=10
return a
print(test(15))
Su error no tiene nada que ver con que ya se haya definido ... Una variable solo es válida dentro de lo que se denomina alcance: si crea una variable en una función, solo se define en esta función.
def test():
x=17
print(x) # returns 17
test()
print(x) # results in an error.
# All the mumbo jumbo aside, here is an experiment
# to illustrate why this is something useful
# in the language of Python:
a = 15 # This could be read-only, should check docs
def test_1():
b = a + 10 # It is perfectly ok to use ''a''
print(b)
def test_2():
a = a + 10 # Refrain from attempting to change ''a''
print(a)
test_1() # No error
test_2() # UnboundLocalError: ...