C贸mo usar variables globales y no locales en Python

    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!

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *