Cómo usar variables globales y no locales en Python

C

Introducción

En este artículo, analizaremos las variables globales y no locales en Python y cómo usarlas para evitar problemas al escribir código.

Comenzaremos con una breve introducción a los ámbitos de las variables antes de comenzar con el cómo y el por qué de usar variables globales y no locales en sus propias funciones.

Ámbitos en Python

Antes de que podamos comenzar, primero tenemos que tocar los visores. Para aquellos de ustedes que están menos familiarizados, “alcance” se refiere al contexto en el que se define una variable y cómo se puede acceder o modificar o, más específicamente, desde dónde se puede acceder.

Y en la programación, como en la vida, el contexto es importante.

Al hacer referencia a Python en este momento, puede inferir del contexto que me refiero al lenguaje de programación. Sin embargo, en otro contexto, Python podría ser una referencia a una serpiente o un grupo cómico.

Los alcances globales y locales son la forma en que su programa comprende el contexto de la variable a la que hace referencia.

Como regla general, las variables definidas dentro de una función o clase (como una variable de instancia) son locales por defecto, y aquellas fuera de funciones y clases son globales por defecto.

Variables locales en Python

Con eso entendido, veámoslo en acción. Comenzaremos definiendo una función con su propia variable local dentro. En esta función tenemos la variable fruit, que inicializamos como una lista e imprimimos:

def shopping_list():
    fruit = ['apple', 'banana']
    print(fruit)
    
shopping_list()

Y como era de esperar, esto funciona de maravilla:

['apple', 'banana']

Pero, ¿qué sucede cuando movemos la declaración print fuera de la función?

def shopping_list():
    fruit = ['apple', 'banana']
    
shopping_list()
print(fruit)

Obtenemos un error ”

Traceback (most recent call last):
  File "<string>", line 5, in <module>
NameError: name 'fruit' is not defined

Específicamente un NameError, ya que la fruta se definió localmente y, por lo tanto, permanece confinada a ese contexto.
Para que nuestro programa comprenda la variable globalmente (fuera de la función), necesitamos definirla globalmente.

Variables globales en Python

¿Qué pasa si en lugar de definir inicialmente nuestra variable dentro de la función, la movemos fuera y la inicializamos allí?

En este caso, podemos referenciarlo fuera de la función y todo funciona.

Pero si intentamos redefinir la variable de fruta dentro shopping_list, esos cambios no se actualizarán a la variable global original, sino que se aislarán localmente:

fruit = ['apple', 'banana']

def shopping_list():
    fruit = ['apple', 'banana', 'grapes']

shopping_list()
print(fruit)

Salida:

['apple', 'banana']

Esto es porque el fruit hemos modificado en el shopping_list() La función es una nueva variable local. Lo creamos, le asignamos un valor y no hicimos nada después de eso. Efectivamente, es un código completamente redundante. los print() declaración imprime el valor de la variable global que está dentro de su alcance.

La palabra clave global

Si queremos que esos cambios se reflejen en nuestra variable global, en lugar de hacer una nueva local, todo lo que tenemos que hacer es agregar el global palabra clave. Esto nos permite comunicar que el fruit variable es de hecho una variable global:

fruit = ['pineapple', 'grapes']

def shopping_list():
    global fruit
    fruit = ['pineapple', 'grapes', 'apple', 'banana']

shopping_list()
print(fruit)

Y efectivamente, la variable global se modifica con los nuevos valores, por lo que llamamos print(fruit), se imprimen los nuevos valores:

['pineapple', 'grapes', 'apple', 'banana']

Al definir el contexto de la variable de fruta a la que nos referimos como global, podemos redefinirlo y modificarlo a nuestro gusto sabiendo que los cambios que hagamos dentro de la función se transferirán.

También podríamos definir una variable global dentro de nuestra función y poder hacer referencia a ella y acceder a ella en cualquier otro lugar.

def shopping_list():
    global fruit
    fruit = ['pineapple', 'grapes', 'apple', 'banana']


shopping_list()
print(fruit)

Esto daría como resultado:

['pineapple', 'grapes', 'apple', 'banana']

Incluso podríamos declarar una variable global dentro de una función y acceder a ella en otra sin especificarla como global en la segunda:

def shopping_list():
    global fruit
    fruit = ['pineapple', 'grapes', 'apple', 'banana']

def print_list():
    print(fruit)
    
shopping_list()
print(fruit)
print_list()

Esto resulta en:

['pineapple', 'grapes', 'apple', 'banana']
['pineapple', 'grapes', 'apple', 'banana']

Precaución al usar variables globales

Si bien poder modificar una variable global localmente es una pequeña herramienta útil, debe tratarla con un poco de precaución. La reescritura excesiva y la anulación del alcance es una receta para el desastre que termina con errores y comportamiento inesperado.

Siempre es importante asegurarse de que está manipulando una variable solo en el contexto en el que la necesita y, de lo contrario, dejarla sola, esta es la principal motivación detrás del principio de encapsulación.

Echaremos un vistazo rápido a un ejemplo de un problema potencial antes de pasar a algunas de las formas en que las variables globales pueden ser útiles en su propio código:

fruit = ['pineapple', 'grapes', 'apple', 'banana']

def first_item():
    global fruit
    fruit = fruit[0]
    
def iterate():
    global fruit
    for entry in fruit:
        print(entry)
    
iterate()
print(fruit)
first_item()
print(fruit)

Ejecutando el código anterior, obtenemos el siguiente resultado:

pineapple
grapes
apple
banana
['pineapple', 'grapes', 'apple', 'banana']
pineapple

En este ejemplo, hacemos referencia a la variable en ambas funciones, first_item() y iterate(). Todo parece funcionar bien si llamamos iterate() y entonces first_item().

Si invertimos ese orden o intentamos iterar después, nos encontramos con un gran problema:

first_item()
print(fruit)
iterate()
print(fruit)

Esto ahora da como resultado:

pineapple
p
i
n
e
a
p
p
l
e
pineapple

A saber, fruit ahora es una cadena que se iterará. Lo que es peor es que este error no se presentará hasta que probablemente sea demasiado tarde. El primer código funcionó aparentemente bien.

Ahora bien, este problema es obvio a propósito. Alteramos una variable global directamente; he aquí, ha cambiado. Sin embargo, en estructuras más complejas, uno podría llevar accidentalmente la modificación de la variable global demasiado lejos y obtener resultados inesperados.

La palabra clave no local

El hecho de que deba ser cauteloso no significa que las variables globales no sean también increíblemente útiles. Las variables globales pueden ser útiles siempre que desee actualizar una variable sin proporcionarla en la declaración de retorno, como un contador. También son muy útiles con funciones anidadas.

Para aquellos de ustedes que usan Python 3+, pueden hacer uso de nonlocal, una palabra clave que funciona de manera muy similar a global, pero tiene efecto principalmente cuando se anida en métodos. nonlocal esencialmente forma un intermedio de alcance global y local.

Dado que hemos estado usando listas de compras y frutas para la mayoría de nuestros ejemplos, podríamos pensar en una función de pago que suma el total de las compras:

def shopping_bill(promo=False):
    items_prices = [10, 5, 20, 2, 8]
    pct_off = 0

    def half_off():
        nonlocal pct_off
        pct_off = .50

    if promo:
        half_off()

    total = sum(items_prices) - (sum(items_prices) * pct_off)
    print(total)
    
shopping_bill(True)

Al ejecutar el código anterior, obtenemos el resultado:

22.5

De esta forma, la variable de conteo global sigue siendo local a la función externa y no afectará (ni existirá) en un nivel superior. Esto le da cierta libertad para agregar modificadores a sus funciones.

Siempre puede confirmar esto intentando imprimir pct_off fuera del método de factura de compra:

NameError: name 'pct_off' is not defined

Si hubiéramos usado el global palabra clave en lugar de la nonlocal palabra clave, impresión pct_off resultaría en:

0.5

Conclusión

Al final del día, las palabras clave globales (y no locales) son una herramienta, y cuando se usan correctamente pueden abrir muchas posibilidades para su código. Personalmente, uso estas dos palabras clave con bastante frecuencia en mi propio código, y con la práctica suficiente llegará a ver lo poderosas y útiles que pueden ser realmente.

Como siempre, ¡muchas gracias por leer y Happy Hacking!

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad