Ámbito local y global de las variables en Python

Los parámetros y variables que se asignan en una función llamada se dice que existen en el ámbito local de esa función. Las variables que se asignan fuera de todas las funciones se dice que existen en el ámbito global. Una variable que existe en el ámbito local se llama variable local, mientras que una variable que existe en el ámbito global se llama variable global. Una variable debe ser una u otra; no puede ser tanto local como global.

Piensa en un ámbito como un contenedor de variables. Cuando un ámbito se destruye, todos los valores almacenados en las variables del ámbito se olvidan. Sólo hay un ámbito global, y se crea cuando se inicia el programa. Cuando tu programa termina, el ámbito global se destruye, y todas sus variables se olvidan. De lo contrario, la próxima vez que ejecute un programa, las variables recordarían sus valores de la última vez que lo ejecutó.

Un ámbito local se crea cada vez que se llama a una función. Cualquier variable asignada en la función existe dentro del ámbito local de la función. Cuando la función retorna, el ámbito local se destruye, y estas variables se olvidan. La próxima vez que se llame a la función, las variables locales no recordarán los valores almacenados en ellas desde la última vez que se llamó a la función. Las variables locales también se almacenan en objetos marco en la pila de llamadas.

Los ámbitos son importantes por varias razones:

  • El código en el ámbito global, fuera de todas las funciones, no puede utilizar ninguna variable local.
  • Sin embargo, el código en un ámbito local puede acceder a las variables globales.
  • El código en el ámbito local de una función no puede usar variables en ningún otro ámbito local.
  • Puedes usar el mismo nombre para diferentes variables si están en diferentes ámbitos. Es decir, puede haber una variable local llamada spam y una variable global también llamada spam.

La razón por la que Python tiene diferentes ámbitos en lugar de hacer que todo sea una variable global es para que cuando las variables son modificadas por el código en una llamada particular a una función, la función interactúa con el resto del programa sólo a través de sus parámetros y el valor de retorno. Esto reduce el número de líneas de código que pueden estar causando un error. Si su programa no contiene más que variables globales y tiene un fallo debido a que una variable se ha establecido en un valor incorrecto, entonces sería difícil rastrear dónde se estableció este valor incorrecto. Podría haberse establecido en cualquier parte del programa, ¡y tu programa podría tener cientos o miles de líneas! Pero si el fallo está causado por una variable local con un valor erróneo, sabes que sólo el código de esa función podría haberlo establecido incorrectamente.

Mientras que el uso de variables globales en programas pequeños está bien, es un mal hábito confiar en las variables globales a medida que tus programas se hacen más y más grandes.

Las variables locales no pueden utilizarse en el ámbito global

Considere este programa, que causará un error cuando lo ejecute:

def spam():
➊ eggs = 31337
spam()
print(eggs)

Si ejecuta este programa, la salida tendrá el siguiente aspecto:

Traceback (most recent call last):
  File "C:/test1.py", line 4, in <module>
    print(eggs)
NameError: name 'eggs' is not defined

El error se produce porque la variable eggs sólo existe en el ámbito local creado cuando se llama a spam() ➊. Una vez que la ejecución del programa vuelve de spam, ese ámbito local se destruye, y ya no hay una variable llamada eggs. Así que cuando tu programa intenta ejecutar print(eggs), Python te da un error diciendo que eggs no está definido. Esto tiene sentido si lo piensas; cuando la ejecución del programa está en el ámbito global, no existen ámbitos locales, por lo que no puede haber variables locales. Por eso sólo se pueden utilizar variables globales en el ámbito global.

Los ámbitos locales no pueden leer variables en otros ámbitos locales

Se crea un nuevo ámbito local cada vez que se llama a una función, incluso cuando se llama a una función desde otra función. Considere este programa:

  def spam():
    ➊ eggs = 99
    ➋ bacon()
    ➌ print(eggs)

   def bacon():
       ham = 101
    ➍ eggs = 0

➎ spam()

Puedes ver la ejecución de este programa en https://autbor.com/otherlocalscopes/. Cuando el programa se inicia, se llama a la función spam() ➎, y se crea un ámbito local. La variable local egges ➊ se establece en 99. Luego se llama a la función bacon() ➋, y se crea un segundo ámbito local. Pueden existir múltiples ámbitos locales al mismo tiempo. En este nuevo ámbito local, la variable local ham se establece en 101, y una variable local eggs que es diferente a la del ámbito local de spam() también se crea ➍ y se establece en 0.

Cuando bacon() retorna, el ámbito local de esa llamada se destruye, incluyendo su variable eggs. La ejecución del programa continúa en la función spam() para imprimir el valor de eggs ➌. Dado que el ámbito local de la llamada a spam() sigue existiendo, la única variable eggs es la de la función spam(), que se estableció en 99. Esto es lo que imprime el programa.

El resultado es que las variables locales de una función están completamente separadas de las variables locales de otra función.

Leyendo variables globales desde un ámbito local

Considere el siguiente programa:

def spam():
    print(eggs)
eggs = 42
spam()
print(eggs)

Puedes ver la ejecución de este programa en https://autbor.com/readglobal/. Como no hay ningún parámetro llamado eggs ni ningún código que asigne un valor a eggs en la función spam(), cuando se utiliza eggs en spam(), Python lo considera una referencia a la variable global eggs. Por eso se imprime 42 cuando se ejecuta el programa anterior.

Variables locales y globales con el mismo nombre

Técnicamente, es perfectamente aceptable usar el mismo nombre de variable para una variable global y variables locales en diferentes ámbitos en Python. Pero, para simplificar tu vida, evita hacer esto. Para ver lo que ocurre, introduce el siguiente código en el editor de archivos y guárdalo como localGlobalSameName.py:

   def spam():
    ➊ eggs = 'spam local'
       print(eggs)    # prints 'spam local'

   def bacon():
    ➋ eggs = 'bacon local'
       print(eggs)    # prints 'bacon local'
       spam()
       print(eggs)    # prints 'bacon local'

➌ eggs = 'global'
   bacon()
   print(eggs)        # prints 'global'

Cuando se ejecuta este programa, sale lo siguiente:

bacon local
spam local
bacon local
global

Puedes ver la ejecución de este programa en https://autbor.com/localglobalsamename/. En realidad hay tres variables diferentes en este programa, pero confusamente todas se llaman eggs. Las variables son las siguientes:

➊ Una variable llamada eggs que existe en un ámbito local cuando se llama a spam().

➋ Una variable llamada eggs que existe en un ámbito local cuando se llama a bacon().

➌ Una variable llamada eggs que existe en el ámbito global.

Dado que estas tres variables separadas tienen el mismo nombre, puede ser confuso seguir la pista de cuál se está utilizando en un momento dado. Por eso debes evitar usar el mismo nombre de variable en diferentes ámbitos.

La sentencia global

Si necesitas modificar una variable global desde una función, utiliza la sentencia global. Si tienes una línea como global eggs al principio de una función, le dice a Python: «En esta función, eggs se refiere a la variable global, así que no crees una variable local con este nombre«. Por ejemplo, introduce el siguiente código en el editor de archivos y guárdalo como globalStatement.py:

def spam():
  ➊ global eggs
  ➋ eggs = 'spam'

eggs = 'global'
spam()
print(eggs)

Cuando ejecute este programa, la llamada final a print() mostrará lo siguiente

spam

Puedes ver la ejecución de este programa en https://autbor.com/globalstatement/. Debido a que eggs se declara global en la parte superior de spam() ➊, cuando eggs se establece como ‘spam‘ ➋, esta asignación se hace a los eggs de ámbito global. No se crea ninguna variable local de eggs.

¿Cómo saber si una variable está en un ámbito local o global?

  • Si una variable se está utilizando en el ámbito global (es decir, fuera de todas las funciones), entonces siempre es una variable global.
  • Si hay una sentencia global para esa variable en una función, es una variable global.
  • En caso contrario, si la variable se utiliza en una sentencia de asignación en la función, es una variable local.
  • Pero si la variable no se utiliza en una sentencia de asignación, es una variable global.

Para entender mejor estas reglas, aquí hay un programa de ejemplo. Introduce el siguiente código en el editor de archivos y guárdalo como sameNameLocalGlobal.py:

def spam():
  ➊ global eggs
     eggs = 'spam' # this is the global

def bacon():
  ➋ eggs = 'bacon' # this is a local

def ham():
  ➌ print(eggs) # this is the global

eggs = 42 # this is the global
spam()
print(eggs)

En la función spam(), eggs es la variable global eggs porque hay una declaración global para eggs al principio de la función ➊. En bacon(), eggs es una variable local porque hay una sentencia de asignación para ella en esa función ➋. En ham() ➌, eggs es la variable global porque no hay ninguna declaración de asignación o declaración global para ella en esa función. Si ejecuta sameNameLocalGlobal.py, la salida se verá así:

spam

Puedes ver la ejecución de este programa en https://autbor.com/sameNameLocalGlobal/. En una función, una variable siempre será global o siempre será local. El código de una función no puede usar una variable local llamada eggs y luego usar la variable global eggs más adelante en esa misma función.

Si alguna vez quieres modificar el valor almacenado en una variable global desde una función, debes utilizar una sentencia global sobre esa variable.

Si intentas utilizar una variable local en una función antes de asignarle un valor, como en el siguiente programa, Python te dará un error. Para ver esto, introduce lo siguiente en el editor de archivos y guárdalo como sameNameError.py:

   def spam():
       print(eggs) # ERROR!
    ➊ eggs = 'spam local'

➋ eggs = 'global'
   spam()

Si ejecutas el programa anterior, produce un mensaje de error.

Traceback (most recent call last):
  File "C:/sameNameError.py", line 6, in <module>
    spam()
  File "C:/sameNameError.py", line 2, in spam
    print(eggs) # ERROR!
UnboundLocalError: local variable 'eggs' referenced before assignment

Puedes ver la ejecución de este programa en https://autbor.com/sameNameError/. Este error se produce porque Python ve que hay una sentencia de asignación para eggs en la función spam() ➊ y, por tanto, considera que eggs es local. Pero como print(eggs) se ejecuta antes de que se asigne algo a eggs, la variable local eggs no existe. Python no volverá a utilizar la variable global eggs ➋.

Funciones como «cajas negras»

A menudo, todo lo que necesitas saber sobre una función son sus entradas (los parámetros) y su valor de salida; no siempre tienes que preocuparte de cómo funciona realmente el código de la función. Cuando se piensa en las funciones de esta manera de alto nivel, es común decir que se está tratando una función como una «caja negra».

Esta idea es fundamental para la programación moderna. Los capítulos posteriores de este libro te mostrarán varios módulos con funciones que fueron escritas por otras personas. Aunque puedes echar un vistazo al código fuente si tienes curiosidad, no necesitas saber cómo funcionan estas funciones para poder utilizarlas. Y dado que se fomenta la escritura de funciones sin variables globales, normalmente no tienes que preocuparte de que el código de la función interactúe con el resto de tu programa.

Deja una respuesta