Variables Locales, No Locales y Globales en Python

Variables locales y globales en Python

A veces nos hacemos un pequeño lío con las variables locales y las variables globales. No sabemos cómo usarlas, cuándo usarlas y, lo que es peor, nuestros programas hacen cosas raras por culpa de ellas. Por si fuera poco, Python introduce además el concepto de variables no locales. Te cuento en este artículo todo lo que tienes que saber acerca del ámbito de las variables y de cómo manejarlas en Python para que te quede todo mucho más claro.

En Python las variables locales son las que se definen en una función y que solo permiten su acceso desde ella. Las globales se definen en el cuerpo principal del programa y permiten su acceso desde cualquier lugar. Las no locales son variables locales que se pueden modificar en funciones anidadas.

Te explico a continuación qué es el ámbito de una variable (o scope en inglés), los tipos de ámbitos que hay, los diferentes tipos de variables y los dos errores principales asociados al uso de variables. También te muestro distintos ejemplos de todo esto. Si además de esto quieres ampliar información puedes leer este artículo acerca de las variables de instancia y las variables de clase en Python.

Para comprender mejor este artículo recuerda que las variables en Python no se declaran. La expresión «definir una variable» toma sentido al entender que las variables se crean cuando se les da valor por primera vez. Durante el artículo asumo que definir una variable hace referencia a este hecho, es decir, a que la variable se crea al darle valor por primera vez.

Ámbito de una variable

El ámbito de una variable es el contexto en el que existe esa variable. Así, una variable existe en dicho ámbito a partir del momento en que se crea y deja de existir cuando desaparece su ámbito.

Además, las variables son accesibles solo desde su propio ámbito, pero con alguna excepción, como veremos más adelante.

Los principales tipos de ámbitos en Python son dos:

  • Ámbito local: corresponde con el ámbito de una función, que existe desde que se invoca a una función hasta que termina su ejecución. En un programa, el ámbito local corresponde con las líneas de código de una función. Dicho ámbito se crea cada vez que se invoca a la función. Cada función tiene su ámbito local. No se puede acceder a las variables de una función desde fuera de esa función o desde otra función.
  • Ámbito global: corresponde con el ámbito que existe desde el comienzo de la ejecución de un programa. Todas las variables definidas fuera de cualquier función corresponden al ámbito global, que es accesible desde cualquier punto del programa, incluidas las funciones. Si desde un módulo A importamos un módulo B mediante un import, desde A podremos acceder a las variables globales de B.

Variables locales

En Python las variables locales son aquellas definidas dentro de una función. Solamente son accesibles desde la propia función y dejan de existir cuando esta termina su ejecución. Los parámetros de una función también son considerados como variables locales.

Es decir, las variables locales son aquellas de ámbito local. Los parámetros de las funciones también se consideran variables locales, y por tanto su ámbito también es local. La diferencia entre los parámetros de una función y las variables locales definidas dentro de una función radica en que los parámetros nos permiten comunicarnos con la función para introducir valores de entrada a través de ellos.

Recuerda que cualquier variable local, incluidos los parámetros, deja de existir en cuanto termina de ejecutarse la función en la que está definida.

Desde el cuerpo principal del programa no se puede acceder a las variables locales de ninguna función. Tampoco es posible acceder a las variables locales de una función desde otra.

Te muestro un pequeño ejemplo a continuación en donde se trabaja con distintas variables locales:

def saludar():
	saludo = '¡Hola!' #esta variable local pertenece al ámbito local de la función saludar
	print(saludo)


def sumar(sumando1, sumando2):
	#sumando1, sumando2 y suma son variables locales que corresponden al ámbito local de la función sumar
	suma = sumando1 + sumando2

	return suma


saludar()
print(sumar(4, 5))

En el ejemplo anterior se definen dos funciones, cada una de las cuales posee su ámbito local. Las variables y parámetros definidos dentro de cada una de ellas son solo accesibles desde su ámbito. Es decir, no podremos acceder a la variable saludo desde la función suma o a la variable sumando1 desde el cuerpo principal del programa.

El error NameError

Si intentamos acceder al valor de una variable local desde el cuerpo principal del programa o, en general, a una variable que no ha sido definida obtendremos un error típico de Python: NameError. Te muestro un ejemplo:

def saludar():
	saludo = '¡Hola!' 
	print(saludo)

saludar()
print(saludo)

Al ejecutar el código anterior se nos mostrará el saludo por pantalla debido a la llamada a la función saludar. Después, al intentar mostrar el valor de la variable saludo desde el cuerpo principal del programa, Python nos «obsequiará» con el mensaje NameError: name 'saludo' is not defined.

Variables globales

Las variables globales en Python son aquellas definidas en el cuerpo principal del programa fuera de cualquier función. Son accesibles desde cualquier punto del programa, incluso desde dentro de funciones. También se puede acceder a las variables globales de otros programas o módulos importados.

Por esto decimos que las variables globales son aquellas de ámbito global. Te enseño un ejemplo donde se puede observar cómo se permite el acceso a las variables globales desde dentro de una función:

def saludar():
	print(saludo)


saludo = '¡Hola, Mundo!' #variable global definida en el cuerpo principal del programa
saludar()

Si ejecutas el código anterior comprobarás como la función saludar imprime por pantalla el contenido de la variable saludo. Fíjate que esto es así aunque la variable saludo se defina y tome valor después de la definición de la función, como es el caso, pues en el momento de ejecutarse dicha función la variable ya existe en el ámbito global.

Accediendo a una variable global de otro módulo

Si en un módulo o programa determinado hay definida alguna variable global podremos acceder a ella importando dicho módulo. Te lo reflejo en un ejemplo muy sencillo:

saludo = '¡Hola, Mundo!'

Ese será nuestro módulo que tiene una única variable global. Ahora creamos un programa desde el que importaremos el módulo modulo.py. De esa manera podremos usar la variable global saludo:

from modulo import saludo #importamos la variable saludo de modulo


def saludar():
	print(saludo)

saludar()

Fíjate que en el código inmediatamente anterior no hay definida ninguna variable llamada saludo pero sí la estamos importando en la línea 1 y por tanto podremos usarla, por ejemplo, dentro de la función saludar. Al ejecutar este programa obtendremos el siguiente resultado por pantalla:

¡Hola, Mundo!

Cómo modificar una variable global desde una función

Las variables globales se pueden leer, como ya he dicho, desde cualquier línea del programa simplemente haciendo referencia a ellas a través de su nombre. Pero ¿qué pasa si intentamos modificar una variable global desde dentro de una función? Ejemplo:

contador = 10

def reiniciar_contador():
	contador = 0


print(f'Contador antes es {contador}')
reiniciar_contador()
print(f'Contador después es {contador}')

En el ejemplo anterior tenemos una variable global contador que en un caso real nos serviría para contar cualquier cosa. También disponemos de una función que nos permite reiniciar el contador cuando queramos. Al ejecutar el código lo esperable sería obtener por pantalla los valores 10 y 0, pero en su lugar tenemos lo siguiente:

Contador antes es 10
Contador después es 10

Esto sucede así no por capricho, sino porque es un mecanismo de protección para evitar modificar sin querer una variable global que posiblemente terminaría alterando el funcionamiento normal de un programa.

Otra cosa que sucede al hacer lo anterior es que la línea contador = 0 ha creado una variable local en el ámbito local de la función reiniciar_contador que se llama exactamente igual que la variable global y a la que ha dado el valor 0.

Para ganar acceso de modificación es necesario utilizar el modificador global. Con esta declaración le estamos diciendo a Python que sabemos que vamos a utilizar una variable global y que queremos modificarla. Veamos el ejemplo corregido y su ejecución:

contador = 10

def reiniciar_contador():
	global contador
	contador = 0


print(f'Contador antes es {contador}')
reiniciar_contador()
print(f'Contador después es {contador}')
Contador antes es 10
Contador después es 0

Ahora sí, gracias al modificador, hemos logrado el comportamiento que queríamos.

Variable local con el mismo nombre que una variable global

A veces puede suceder, como vimos anteriormente, que dentro de una función existe una variable local con el mismo nombre que una variable global, es decir, sus nombres entran en conflicto.

Tienes que saber que cuando hacemos referencia a una variable Python busca primero en el ámbito local actual para ver si encuentra dicha variable y si no, la busca en el ámbito global. Es decir, en cierta forma, el ámbito local tiene preferencia sobre el global. Se puede decir que la variable local le hace sombra a la variable global. Veamos un ejemplo:

valor = 10

def funcion():
	valor = 20
	print(f'Valor en función es {valor}')


funcion()
print(f'Valor en cuerpo principal es {valor}')

Si te fijas verás que en la función funcion se define una variable valor que toma el valor 20. No obstante ya existe una variable global llamada de la misma manera con valor 10. Al ejecutar el código se obtiene lo siguiente:

Valor en función es 20
Valor en cuerpo principal es 10

Con esto queda de manifiesto que al hacer referencia a la variable valor desde dentro de la función se accede a la variable local, es decir, se da preferencia al ámbito local.

El error UnboundLocalError

A veces nos salta en un programa el error UnboundLocalError que nos puede volver un poco locos porque puede ser algo difícil de entender, pero te lo voy a aclarar.

La excepción UnboundLocalError en Python se lanza cuando se hace referencia a una variable local dentro de una función pero esa variable todavía no tiene valor.

Esto está muy relacionado con el error NameError, que ya vimos, de hecho deriva de él, y con el caso en que tenemos variables locales con el mismo nombre que variables globales. Veamos un ejemplo sencillo en donde sucede:

valor = 10

def funcion_con_error():
	print(f'Valor antes es es {valor}')
	valor = 20
	print(f'Valor desués es es {valor}')


funcion_con_error()

En este ejemplo tenemos una variable global con valor 10 y una función en la que se intenta poner a 20 dicha variable. Al ejecutar este código la ejecución del programa se detiene con el siguiente mensaje: UnboundLocalError: local variable 'valor' referenced before assignment. Se puede traducir como «se hace referencia a la variable local ‘valor’ antes de su asignación».

¿Qué está pasando? Lo que ha sucedido ahí es lo siguiente. El compilador de Python al ejecutar la función crea el ámbito local para la misma. No obstante, antes de ejecutar ninguna línea comprueba que la variable valor se va a definir como variable local pues hay una asignación en el código. Como previamente se intenta mostrar por pantalla el valor de dicha variable, que Python entiende que es local, al no tener valor todavía el programa se detendrá mostrando el error.

Para evitar este error tenemos que tener muy claro lo que queremos hacer, que pueden ser dos cosas:

  1. Si pretendemos modificar el valor de la variable global valor ya sabes lo que tienes que hacer, que es usar el modificador global incluyendo la línea global valor al comienzo de la función.
  2. Si lo que queremos es una variable local que no tenga nada que ver con la variable global la mejor opción es utilizar un nombre de variable diferente para eliminar el conflicto.

Recomendación. En general es mejor no utilizar variables globales. Normalmente son totalmente evitables y nos ahorramos muchos problemas y quebraderos de cabeza. Si necesitas que las funciones accedan a valores externos, ya sea para lectura o escritura, utiliza los parámetros de las funciones y su mecanismo de devolución de valores return.

Variables no locales

A pesar de lo que se lee, se explica y se cree por ahí, las variables no locales no existen en Python. En realidad son un mecanismo que nos permite hacer acceso de escritura de una variable local desde dentro de otra función definida en el mismo ámbito, es decir, desde una función anidada. Pero vayamos por partes.

Una función anidada en Python es una función A que se define dentro de otra función P y que solo puede ser utilizada desde la función P.

Si definimos una variable local dentro de la función P podremos acceder a ella desde la función anidada A, pero solo para leerla. Si queremos modificar su valor tendremos que utilizar el modificador nonlocal. Sucede exactamente lo mismo cuando queremos modificar una variable global desde dentro de una función.

Cuidado, el modificador nonlocal no existe en Python 2, es exclusivo de Python 3 (otro buen motivo para actualizarte si todavía no lo has hecho).

Dicho con otras palabras una variable local actúa como variable global para las funciones anidadas dentro de su mismo contexto.

Te lo aclaro con ejemplos:

def funcion_padre():
	valor = 10

	def funcion_anidada():
		valor = 20
		print(f'Valor en función anidada es {valor}')

	print(f'Valor en función padre antes es {valor}')
	funcion_anidada()
	print(f'Valor en función padre después es {valor}')

funcion_padre()

Al ejecutar el código anterior obtenemos el siguiente resultado por pantalla:

Valor en función padre antes es 10
Valor en función anidada es 20
Valor en función padre después es 10

Lo que sucede en la función anidada es que al asignar 20 a la variable valor se crea una variable local en el ámbito local de la función funcion_anidada y, por tanto, la variable local valor del ámbito de la función funcion_padre permanece inalterada.

Como sucedía en el caso de querer modificar una variable global y de manera análoga, podemos modificar la variable si utilizamos el modificador nonlocal de la siguiente manera:

def funcion_padre():
	valor = 10

	def funcion_anidada():
		nonlocal valor
		valor = 20
		print(f'Valor en función anidada es {valor}')

	print(f'Valor en función padre antes es {valor}')
	funcion_anidada()
	print(f'Valor en función padre después es {valor}')

funcion_padre()

Con esto obtenemos el siguiente resultado por pantalla:

Valor en función padre antes es 10
Valor en función anidada es 20
Valor en función padre después es 20

Función globals() y función locals()

Para ir concluyendo este artículo te diré que en Python existen dos funciones que tienen mucho que ver con el registro y el acceso a las diferentes variables globales y locales en cada ámbito.

En Python la función globals() devuelve el diccionario que contiene todas las variables del ámbito global actual. Se puede usar este diccionario para acceder al valor de dichas variables y modificarlo.

La función locals() en Python devuelve un diccionario que contiene todas las variables del ámbito local actual. Se puede utilizar para acceder al valor de las variables locales pero no para modificarlas, pues es un diccionario de solo lectura.

Veamos algunos ejemplos de acceso y modificación de variables utilizando las citadas funciones, teniendo en cuenta que el valor de cada variable está almacenada en el diccionario indexado por el nombre de la propia variable.

valor = 10

def funcion():
	valor = 20
	print(f'La variable local valor es {locals()["valor"]}')
	print(f'La variable global valor es {globals()["valor"]}')

funcion()
globals()['valor'] = 30 #modificamos el valor de la variable a través del diccionario
print(f'La variable global valor es ahora {valor}')

Este código genera el siguiente resultado:

La variable local valor es 20
La variable global valor es 10
La variable global valor es ahora 30

Si te paras a pensarlo te darás cuenta de que esto resuelve uno de los problemas expuestos más arriba. ¿Eres capaz de verlo?

Ten en cuenta que en el cuerpo principal del programa el diccionario devuelto por globals y por locals es el mismo, pues el ámbito local del cuerpo principal es precisamente el ámbito global del programa.

Y con ese último trabalenguas termino. No te olvides de revisar el artículo sobre variables de instancia y variables de clase en Python, creo que junto a este te serán de mucha ayuda para terminar de aclarar todos esos conceptos acerca de las variables que tal vez se te escapen un poco, como me pasó a mí en su momento. Y antes de ponerte a estudiarlo recuerda las 10 cosas que necesitas para aprender a programar en Python.

La Hoja de Referencia de Python – ¡Gratis!

La Hoja de Referencia de Python - Código Pitón
Consigue trucos, consejos y actualizaciones y, por supuesto, la Hoja de Referencia de Python gratis.



Antes de suscribirte consulta aquí la Información Básica sobre Protección de Datos. Responsable de los datos: Laura Otero Moreira. Finalidad de la recogida y tratamiento de los datos personales: enviarte boletín informativo de Python y comunicaciones comerciales. Legitimación: tu consentimiento. Destinatarios: no se ceden a terceros. Los datos se almacenan en los servidores de marketing (MailRelay). Derechos: podrás ejercer tus derechos de acceso, rectificación, limitación y supresión de datos en info @ codigopiton.com así como presentar una reclamación ante una autoridad de control. Más información en nuestra política de privacidad, encontrarás información adicional sobre la recopilación y el uso de tu información personal, incluida información sobre acceso, conservación, rectificación, eliminación, seguridad y otros temas.