Python & AI Tutorials Logo
Programación Python

21. Alcance de variables y resolución de nombres

Cuando creas una variable en Python, ¿dónde “vive”? ¿Puede una función ver variables creadas fuera de ella? ¿Puede el código fuera de una función acceder a variables creadas dentro de ella? Estas preguntas tratan sobre el alcance(scope): la región de tu programa donde un nombre es visible y se puede usar.

Comprender el alcance es crucial para escribir funciones que funcionen correctamente y de forma predecible. Sin este conocimiento, podrías crear bugs accidentalmente en los que las variables no tienen los valores que esperas, o en los que los cambios en las variables no persisten como se pretende.

En este capítulo, exploraremos cómo Python determina a qué variable se refiere un nombre, cómo controlar dónde son accesibles las variables y qué ocurre cuando eliminas un nombre. Al final, comprenderás las reglas que gobiernan la visibilidad de variables en programas de Python.

21.1) Variables locales y globales

Cada variable en Python existe dentro de un alcance(scope) específico: una región de código donde ese nombre de variable está definido y es accesible. Los dos alcances más fundamentales son local y global.

Comprender el alcance global

Las variables creadas en el nivel superior de tu programa —fuera de cualquier función— existen en el alcance global. Estas se llaman variables globales, y son accesibles desde cualquier parte de tu módulo después de que se definan.

python
# Variable global: definida a nivel de módulo
total_users = 0
 
def show_user_count():
    # Esta función puede LEER la variable global
    print(f"Total users: {total_users}")
 
show_user_count()  # Output: Total users: 0
print(total_users)  # Output: 0

En este ejemplo, total_users es una variable global. Tanto la función show_user_count() como el código a nivel de módulo pueden acceder a ella. Piensa en las variables globales como algo visible a lo largo de todo tu archivo de programa.

Comprender el alcance local

Las variables creadas dentro de una función existen en el alcance local de esa función. Estas se llaman variables locales, y solo son accesibles dentro de la función donde se definen. Una vez que la función termina de ejecutarse, las variables locales desaparecen.

python
def calculate_discount(price):
    # discount_rate es LOCAL para esta función
    discount_rate = 0.15
    discount_amount = price * discount_rate
    return discount_amount
 
result = calculate_discount(100)
print(result)  # Output: 15.0
 
# Esto causaría un error: discount_rate no existe aquí
# print(discount_rate)  # NameError: name 'discount_rate' is not defined

Las variables discount_rate y discount_amount existen solo mientras calculate_discount() se está ejecutando. Después de que la función retorna, estos nombres ya no existen. Esto, de hecho, es algo bueno: evita que las funciones llenen tu programa con variables temporales.

Por qué importa el alcance local

El alcance local proporciona encapsulación(encapsulation): cada función tiene su propio espacio de trabajo privado. Esto significa que puedes usar los mismos nombres de variables en distintas funciones sin conflictos:

python
def calculate_tax(amount):
    rate = 0.08  # Variable local
    return amount * rate
 
def calculate_shipping(weight):
    rate = 5.00  # Variable local diferente con el mismo nombre
    return weight * rate
 
tax = calculate_tax(100)
shipping = calculate_shipping(3)
 
print(f"Tax: ${tax}")         # Output: Tax: $8.0
print(f"Shipping: ${shipping}")  # Output: Shipping: $15.0

Ambas funciones usan una variable llamada rate, pero son variables completamente separadas en distintos alcances locales. Los cambios a rate en una función no afectan a rate en la otra función. Este aislamiento hace que las funciones sean más fiables y más fáciles de entender.

Leer variables globales desde funciones

Las funciones pueden leer variables globales sin ninguna sintaxis especial:

python
# Configuración global
max_login_attempts = 3
 
def check_login(password):
    # Leyendo variable global
    if password == "secret123":
        return "Login successful"
    else:
        return f"Invalid password. You have {max_login_attempts} attempts."
 
result = check_login("wrong")
print(result)  # Output: Invalid password. You have 3 attempts.

La función check_login() puede leer max_login_attempts porque es una variable global. Sin embargo, hay una limitación importante que necesitamos entender.

La regla de que una asignación crea variables locales

Aquí es donde el alcance se pone complicado. Si asignas a un nombre de variable dentro de una función, Python crea una nueva variable local con ese nombre, incluso si existe una variable global con el mismo nombre:

python
counter = 0  # Variable global
 
def increment_counter():
    # ADVERTENCIA: Esto crea una NUEVA variable local llamada counter; solo para demostración
    # PROBLEMA: Intentar leer counter antes de asignarle un valor localmente
    counter = counter + 1  # UnboundLocalError: local variable 'counter' referenced before assignment
    print(counter)
 
# increment_counter() # Esta llamada produce UnboundLocalError

Este código falla porque Python ve la asignación counter = counter + 1 y decide que counter debe ser una variable local. Pero luego, cuando intenta evaluar counter + 1, la variable local counter aún no tiene un valor: estamos intentando usarla antes de haberle asignado uno.

Esta es una fuente común de confusión. La regla es: si una función asigna a un nombre de variable en cualquier parte de su cuerpo, ese nombre se trata como local a lo largo de toda la función, incluso antes de la asignación.

Veámoslo más claramente:

python
message = "Hello"  # Variable global
 
def show_message():
    print(message)  # Esto funciona: solo está leyendo la global
    
def change_message():
    # ADVERTENCIA: Esto demuestra un error común; solo para demostración
    # PROBLEMA: Python ve la asignación abajo, así que message se trata como local en toda la función
    print(message)  # UnboundLocalError!
    message = "Goodbye"  # Esto hace que message sea local para TODA la función
 
show_message()  # Output: Hello
# change_message()  # Esta llamada produce UnboundLocalError

La función show_message() funciona bien porque solo lee message. Pero change_message() falla porque la asignación en la segunda línea hace que Python trate message como local en toda la función, incluida la sentencia print() que aparece antes de la asignación.

Los parámetros son variables locales

Los parámetros de una función son variables locales que obtienen sus valores iniciales a partir de los argumentos pasados cuando se llama a la función:

python
def greet(name):  # 'name' es una variable local
    greeting = f"Hello, {name}!"  # 'greeting' también es local
    return greeting
 
message = greet("Alice")
print(message)  # Output: Hello, Alice!
 
# Ni 'name' ni 'greeting' existen aquí
# print(name)  # NameError

El parámetro name existe solo dentro de la función greet(). Se crea cuando se llama a la función y desaparece cuando la función retorna.

Ejemplo práctico: cálculo de un carrito de compras

Veamos cómo el alcance local y global trabajan juntos en un escenario realista:

python
# Configuración global
tax_rate = 0.08
free_shipping_threshold = 50
 
def calculate_total(subtotal):
    # Variables locales para este cálculo
    tax = subtotal * tax_rate  # Leyendo tax_rate global
    
    # Determinar el costo de envío
    if subtotal >= free_shipping_threshold:  # Leyendo el umbral global
        shipping = 0
    else:
        shipping = 5.99
    
    total = subtotal + tax + shipping
    return total
 
# Calcular para diferentes valores del carrito
cart1 = calculate_total(30)
cart2 = calculate_total(60)
 
print(f"Cart 1 total: ${cart1:.2f}")  # Output: Cart 1 total: $38.39
print(f"Cart 2 total: ${cart2:.2f}")  # Output: Cart 2 total: $64.80

En este ejemplo:

  • tax_rate y free_shipping_threshold son valores de configuración global
  • subtotal, tax, shipping y total son locales a cada llamada de calculate_total()
  • Cada llamada de la función obtiene su propio conjunto separado de variables locales
  • La función puede leer la configuración global, pero no la modifica

Esta separación de responsabilidades hace que el código sea claro: las variables globales guardan la configuración que aplica en todas partes, mientras que las variables locales guardan resultados temporales de cálculo específicos para cada llamada a la función.

21.2) La regla LEGB para la resolución de nombres

Cuando Python se encuentra con un nombre de variable, ¿cómo sabe a qué variable te refieres? Python sigue un orden de búsqueda específico llamado la regla LEGB (LEGB rule). LEGB significa Local, Enclosing, Global, Built-in: los cuatro alcances que Python busca, en ese orden.

Los cuatro alcances en LEGB

Entendamos cada alcance en la jerarquía LEGB:

  1. Local (L): el alcance de la función actual
  2. Enclosing (E): el alcance de cualquier función envolvente (funciones que contienen a la función actual)
  3. Global (G): el alcance a nivel de módulo
  4. Built-in (B): los nombres incorporados de Python como print, len, int, etc.

Cuando usas un nombre de variable, Python busca estos alcances en orden: L → E → G → B. Usa la primera coincidencia que encuentra y deja de buscar.

Alcance local: el primer lugar donde Python busca

Python siempre revisa primero el alcance local:

python
def calculate_price():
    price = 100  # Variable local
    tax = 0.08   # Variable local
    total = price * (1 + tax)
    return total
 
result = calculate_price()
print(result)  # Output: 108.0

Cuando Python ve price, tax y total dentro de calculate_price(), los encuentra en el alcance local y usa esos valores. La búsqueda se detiene en el alcance local: Python no necesita buscar más.

Alcance global: cuando lo local no lo tiene

Si un nombre no se encuentra localmente, Python revisa el alcance global:

python
# Variables globales
default_tax_rate = 0.08
default_currency = "USD"
 
def calculate_price(amount):
    # 'amount' es local, se encuentra de inmediato
    # 'default_tax_rate' no es local, se encuentra en el alcance global
    total = amount * (1 + default_tax_rate)
    return total
 
result = calculate_price(100)
print(result)  # Output: 108.0

Cuando Python encuentra default_tax_rate dentro de la función, no lo encuentra localmente, así que busca en el alcance global y lo encuentra allí.

Alcance built-in: nombres predefinidos de Python

Si un nombre no se encuentra en el alcance local ni global, Python revisa el alcance built-in: los nombres que Python proporciona automáticamente:

python
def process_data(numbers):
    # 'numbers' es local
    # 'len' no es local ni global: es built-in
    count = len(numbers)
    
    # 'max' también es built-in
    maximum = max(numbers)
    
    return count, maximum
 
data = [10, 25, 15, 30, 20]
result = process_data(data)
print(result)  # Output: (5, 30)

Los nombres len y max no están definidos en tu código: son funciones incorporadas que Python proporciona. Cuando Python no encuentra estos nombres localmente ni globalmente, revisa el alcance built-in y los encuentra allí.

Alcance envolvente: funciones anidadas

El alcance envolvente entra en juego cuando tienes funciones anidadas: funciones definidas dentro de otras funciones. Aquí es donde la “E” en LEGB se vuelve importante:

python
def outer_function():
    outer_var = "I'm from outer"  # En alcance envolvente para inner_function
    
    def inner_function():
        inner_var = "I'm from inner"  # Local para inner_function
        # inner_function puede ver tanto inner_var (local) como outer_var (envolvente)
        print(inner_var)   # Output: I'm from inner
        print(outer_var)   # Output: I'm from outer
    
    inner_function()
 
outer_function()

Para inner_function(), el alcance de outer_function() es un alcance envolvente. Cuando inner_function() referencia outer_var, Python busca:

  1. Alcance local de inner_function() — no se encuentra
  2. Alcance envolvente de outer_function() — ¡se encuentra! Usa este valor

LEGB en acción: ejemplo simple

Veamos los cuatro alcances trabajando juntos en un ejemplo claro y directo:

python
# Built-in: len (Python proporciona esto)
# Global: multiplier
multiplier = 10
 
def outer(x):
    # Alcance envolvente para inner
    y = 5
    
    def inner(z):
        # Alcance local
        # z es local (L)
        # y es del alcance envolvente (E)
        # multiplier es del alcance global (G)
        # len es del alcance built-in (B)
        result = len([z, y, multiplier])  # ¡Usa los cuatro alcances!
        return z + y + multiplier
 
    return inner(3)
 
answer = outer(100)
print(answer)  # Output: 18

Cuando Python evalúa z + y + multiplier dentro de inner():

  1. L (Local): encuentra z = 3
  2. E (Enclosing): encuentra y = 5 en outer()
  3. G (Global): encuentra multiplier = 10
  4. B (Built-in): encuentra la función len

Este ejemplo demuestra claramente cómo Python busca a través de los cuatro alcances para resolver nombres.

Sombreado: cuando los alcances internos ocultan nombres externos

Si el mismo nombre existe en múltiples alcances, el alcance más interno “gana”: esto se llama sombreado(shadowing):

python
value = "global"
 
def outer():
    value = "enclosing"
    
    def inner():
        value = "local"
        print(value)  # Which value?
    
    inner()
    print(value)  # Which value?
 
outer()
print(value)  # Which value?

Output:

local
enclosing
global

Cada sentencia print() ve un value diferente porque Python se detiene en la primera coincidencia:

  • Dentro de inner(): encuentra value localmente → imprime "local"
  • Dentro de outer() pero fuera de inner(): encuentra value en el alcance de outer() → imprime "enclosing"
  • A nivel de módulo: encuentra value globalmente → imprime "global"

Visualizar el orden de búsqueda LEGB

No

No

No

No

Referencia de nombre

¿Se encuentra en Local?

Usar valor Local

¿Se encuentra en Enclosing?

Usar valor Enclosing

¿Se encuentra en Global?

Usar valor Global

¿Se encuentra en Built-in?

Usar valor Built-in

NameError

Este diagrama muestra el proceso de búsqueda de Python. Empieza en el alcance más interno y va hacia fuera. Si el nombre no se encuentra en ningún alcance, Python lanza un NameError.

Por qué LEGB importa al escribir funciones

Comprender LEGB te ayuda a:

  1. Predecir valores de variables: sabes exactamente qué variable usará Python
  2. Evitar conflictos de nombres: entiendes cuándo los nombres se sombrean entre sí
  3. Diseñar mejores funciones: puedes decidir qué alcance es apropiado para cada variable
  4. Depurar problemas de alcance: cuando las variables no tienen los valores esperados, puedes rastrear LEGB

La regla LEGB es fundamental para cómo Python resuelve nombres. Cada vez que usas una variable, Python está siguiendo esta regla detrás de escena.

21.3) Usar la palabra clave global con cuidado

Hemos visto que las funciones pueden leer variables globales, pero ¿qué pasa si necesitas modificar una variable global desde dentro de una función? Ahí es donde entra la palabra clave global, pero debe usarse con moderación y cuidado.

El problema: la asignación crea variables locales

Como aprendimos antes, asignar a una variable dentro de una función crea una variable local:

python
counter = 0  # Variable global
 
def increment():
    # ADVERTENCIA: Esto crea una NUEVA variable local llamada counter; solo para demostración
    # PROBLEMA: Intentar leer counter antes de asignarle un valor localmente
    counter = counter + 1  # UnboundLocalError!
    
# increment()  # Esta llamada produce UnboundLocalError

Esto falla porque Python ve la asignación y trata counter como local a lo largo de toda la función. Pero estamos intentando leer counter antes de haberle asignado un valor localmente.

Este es uno de los errores más comunes al trabajar con variables globales. El mensaje de error UnboundLocalError: local variable 'counter' referenced before assignment te dice exactamente qué pasó: Python decidió que counter era local (por la asignación), pero intentaste usarla antes de darle un valor.

La solución: declarar variables como global

La palabra clave global le dice a Python: “No crees una nueva variable local con este nombre. Usa la variable global en su lugar.”

python
counter = 0  # Variable global
 
def increment():
    global counter  # Decirle a Python que use el counter global
    counter = counter + 1  # Ahora esto modifica la variable global
 
print(f"Before: {counter}")  # Output: Before: 0
increment()
print(f"After: {counter}")   # Output: After: 1
increment()
print(f"After again: {counter}")  # Output: After again: 2

La declaración global counter debe ir antes de usar la variable. Le dice a Python que cualquier asignación a counter en esta función debe modificar la variable global, no crear una local.

Múltiples variables globales

Puedes declarar múltiples variables como global en una sola sentencia:

python
total_sales = 0
total_customers = 0
 
def record_sale(amount):
    global total_sales, total_customers
    total_sales += amount
    total_customers += 1
 
print(f"Sales: ${total_sales}, Customers: {total_customers}")
# Output: Sales: $0, Customers: 0
 
record_sale(25.50)
record_sale(30.00)
 
print(f"Sales: ${total_sales}, Customers: {total_customers}")
# Output: Sales: $55.5, Customers: 2

Tanto total_sales como total_customers se declaran globales, así que la función puede modificar ambas.

Cuándo usar global: estado compartido

La palabra clave global es apropiada cuando necesitas mantener estado compartido(shared state): datos a los que múltiples funciones necesitan acceder y modificar:

python
# Estado del juego
player_score = 0
player_lives = 3
game_over = False
 
def award_points(points):
    global player_score
    player_score += points
    print(f"Score: {player_score}")
 
def lose_life():
    global player_lives, game_over
    player_lives -= 1
    print(f"Lives remaining: {player_lives}")
    
    if player_lives <= 0:
        game_over = True
        print("Game Over!")
 
def check_game_status():
    # Solo leyendo globales: no hace falta la palabra clave global
    if game_over:
        return "Game Over"
    else:
        return f"Playing - Score: {player_score}, Lives: {player_lives}"
 
# Jugar el juego
award_points(100)    # Output: Score: 100
award_points(50)     # Output: Score: 150
lose_life()          # Output: Lives remaining: 2
print(check_game_status())  # Output: Playing - Score: 150, Lives: 2

Este ejemplo muestra un uso apropiado de global: múltiples funciones necesitan modificar el estado compartido del juego. Sin embargo, nota que check_game_status() no necesita global porque solo lee las variables.

Por qué global debe usarse con cuidado

Aunque global a veces es necesario, abusar de él puede hacer que el código sea más difícil de entender y mantener. Aquí tienes por qué:

Problema 1: dependencias ocultas

Cuando las funciones modifican variables globales, no es obvio desde la llamada a la función qué está cambiando:

python
total = 0
 
def add_to_total(value):
    global total
    total += value
 
# ¿Qué hace esta función? No puedes saberlo sin leer su código
add_to_total(10)

Compara esto con una función que devuelve un valor:

python
def add_to_total(current_total, value):
    return current_total + value
 
total = 0
total = add_to_total(total, 10)  # Claro: total se está actualizando

La segunda versión hace explícito que total se está modificando.

Problema 2: las pruebas se vuelven más difíciles

Las funciones que modifican estado global son más difíciles de probar porque necesitas preparar y restablecer variables globales:

python
# Difícil de probar: depende del estado global
score = 0
 
def add_score(points):
    global score
    score += points
 
# Cada prueba necesita restablecer score
# Test 1
score = 0
add_score(10)
assert score == 10
 
# Test 2: hay que restablecer score de nuevo
score = 0
add_score(20)
assert score == 20

Problema 3: las funciones no son reutilizables

Las funciones que dependen de variables globales específicas no se pueden reutilizar fácilmente en otros programas:

python
# Esta función solo funciona si hay una variable global llamada 'inventory'
inventory = []
 
def add_item(item):
    global inventory
    inventory.append(item)

Mejores alternativas a global

En muchos casos, puedes evitar global usando valores de retorno y parámetros:

En vez de modificar estado global:

python
# Usando global (menos ideal)
balance = 1000
 
def withdraw(amount):
    global balance
    if amount <= balance:
        balance -= amount
        return True
    return False
 
withdraw(100)
print(balance)  # Output: 900

Usa valores de retorno:

python
# Usando valores de retorno (mejor)
def withdraw(balance, amount):
    if amount <= balance:
        return balance - amount, True
    return balance, False
 
balance = 1000
balance, success = withdraw(balance, 100)
print(balance)  # Output: 900

La segunda versión es más flexible, más fácil de probar y más reutilizable.

Cuándo global es realmente apropiado

Hay usos legítimos de global:

  1. Configuración que realmente necesita ser global:
python
# Ajustes de toda la aplicación
debug_mode = False
log_level = "INFO"
 
def enable_debug():
    global debug_mode, log_level
    debug_mode = True
    log_level = "DEBUG"
  1. Contadores para depuración o estadísticas:
python
# Rastrear llamadas a la función para depuración
_function_call_count = 0
 
def tracked_function():
    global _function_call_count
    _function_call_count += 1
    # ... resto de la función

Puntos clave sobre global

  • Usa global solo cuando realmente necesitas modificar estado a nivel de módulo
  • Prefiere devolver valores y usar parámetros en su lugar
  • Cuando uses global, documenta por qué es necesario
  • Considera si tu diseño podría mejorarse para evitar global
  • Recuerda: leer variables globales no requiere la palabra clave global; solo modificarlas lo requiere

21.4) Usar nonlocal para modificar variables en funciones envolventes

Cuando tienes funciones anidadas, podrías necesitar modificar una variable del alcance de una función envolvente. La palabra clave nonlocal sirve para esto: es como global, pero para alcances de funciones envolventes en lugar del alcance global.

El problema: modificar variables envolventes

Así como la asignación crea variables locales por defecto, el mismo problema ocurre con los alcances envolventes:

python
def outer():
    count = 0  # Variable en el alcance de outer
    
    def inner():
        # ADVERTENCIA: Esto crea una NUEVA variable local llamada count; solo para demostración
        # PROBLEMA: Intentar leer count antes de asignarle un valor localmente
        count = count + 1  # UnboundLocalError!
        print(count)
    
    inner()
 
# outer()  # Esta llamada produce UnboundLocalError

Python ve la asignación a count en inner() y la trata como una variable local. Pero estamos intentando leerla antes de asignarla localmente, causando un error.

La solución: la palabra clave nonlocal

La palabra clave nonlocal le dice a Python: “Esta variable no es local; búscala en el alcance de la función envolvente y usa esa.”

python
def outer():
    count = 0  # Variable en el alcance de outer
    
    def inner():
        nonlocal count  # Usar el count del alcance de outer
        count = count + 1
        print(f"Count in inner: {count}")
    
    print(f"Count before: {count}")  # Output: Count before: 0
    inner()                          # Output: Count in inner: 1
    print(f"Count after: {count}")   # Output: Count after: 1
 
outer()

Ahora inner() puede modificar la variable count del alcance de outer(). El cambio persiste después de que inner() retorna porque estamos modificando la variable real en el alcance envolvente.

Por qué nonlocal es útil: funciones que recuerdan estado

La palabra clave nonlocal habilita un patrón potente donde las funciones internas pueden mantener y modificar estado del alcance envolvente. Aprenderemos sobre closures y funciones fábrica en detalle en el Capítulo 23, pero por ahora, entiende que nonlocal permite que las funciones internas modifiquen variables de alcances envolventes.

Aquí tienes un ejemplo simple que muestra cómo funciona nonlocal:

python
def create_counter():
    count = 0  # Esta variable está en el alcance envolvente para increment
    
    def increment():
        nonlocal count  # Modificar count desde el alcance envolvente
        count += 1
        return count
    
    return increment  # Devolver la función interna
 
# Crear un contador
counter1 = create_counter()
 
print(counter1())  # Output: 1
print(counter1())  # Output: 2
print(counter1())  # Output: 3
 
# Crear otro contador independiente
counter2 = create_counter()
 
print(counter2())  # Output: 1
print(counter2())  # Output: 2

Cada llamada a create_counter() crea una nueva variable count y una nueva función increment() que puede modificar ese count específico usando nonlocal.

nonlocal vs global

Es importante entender la diferencia:

python
x = "global"
 
def outer():
    x = "enclosing"
    
    def use_global():
        global x  # Se refiere al x global
        print(f"use_global sees: {x}")  # Output: use_global sees: global
    
    def use_nonlocal():
        nonlocal x  # Se refiere al x de outer
        print(f"use_nonlocal sees: {x}")  # Output: use_nonlocal sees: enclosing
    
    use_global()
    use_nonlocal()
 
outer()
  • global siempre se refiere al alcance a nivel de módulo
  • nonlocal se refiere al alcance de la función envolvente más cercano

Cuándo no puedes usar nonlocal

La palabra clave nonlocal solo funciona con alcances de funciones envolventes. No puedes usarla para:

  1. Alcance global (usa global en su lugar):
python
x = "global"
 
def func():
    nonlocal x  # SyntaxError: no binding for nonlocal 'x' found
    x = "modified"
  1. Variables que no existen en ningún alcance envolvente:
python
def outer():
    def inner():
        nonlocal count  # SyntaxError: no binding for nonlocal 'count' found

Puntos clave sobre nonlocal

  • Usa nonlocal para modificar variables de alcances de funciones envolventes
  • nonlocal busca alcances de funciones envolventes, no el alcance global
  • Leer variables envolventes no requiere nonlocal; solo modificarlas lo requiere
  • nonlocal habilita patrones potentes para crear funciones con estado privado
  • Aprenderemos más sobre closures y funciones fábrica en el Capítulo 23

La palabra clave nonlocal es particularmente útil para crear funciones que mantienen estado privado, como vimos con los ejemplos de contador, cuenta y rastreador de eventos.

21.5) Eliminar nombres (no objetos) con del y qué significa

A veces necesitas eliminar una variable del espacio de nombres de tu programa: quizá para liberar memoria en programas de larga ejecución, limpiar variables temporales o eliminar entradas de colecciones. La sentencia del de Python maneja estas tareas, pero es importante entender exactamente qué hace y qué no hace.

La sentencia del en Python a menudo se malinterpreta. No elimina objetos: elimina nombres (vinculaciones de variables). Comprender esta distinción es crucial para entender cómo Python gestiona la memoria y las referencias.

Qué hace realmente del

La sentencia del elimina un nombre del alcance actual:

python
x = 42
print(x)  # Output: 42
 
del x
 
# print(x)  # NameError: name 'x' is not defined

Después de del x, el nombre x ya no existe en el alcance actual. Si intentas usarlo, Python lanza un NameError porque el nombre ya no está definido.

Eliminar nombres vs eliminar objetos

Esta es la idea clave: del elimina el nombre, no necesariamente el objeto al que se refiere el nombre:

python
# Crear una lista y dos nombres que se refieren a ella
original = [1, 2, 3]
reference = original  # Ambos nombres se refieren a la misma lista
 
print(original)   # Output: [1, 2, 3]
print(reference)  # Output: [1, 2, 3]
 
# Eliminar un nombre
del original
 
# La lista aún existe porque 'reference' todavía se refiere a ella
print(reference)  # Output: [1, 2, 3]
 
# print(original)  # NameError: name 'original' is not defined

La lista [1, 2, 3] sigue existiendo porque reference todavía se refiere a ella. Eliminar original solo eliminó ese nombre: no eliminó el objeto lista en sí.

Cuándo los objetos se eliminan de verdad

Python elimina automáticamente los objetos cuando ya no son referenciados por ningún nombre. A esto se le llama recolección de basura(garbage collection):

python
data = [1, 2, 3]  # Se crea la lista, 'data' se refiere a ella
 
del data  # Se elimina el nombre 'data'
 
# Ahora la lista no tiene referencias, así que Python eventualmente la eliminará
# (Esto ocurre automáticamente: no necesitas hacer nada)

Cuando eliminamos data, la lista [1, 2, 3] no tiene referencias restantes, así que el recolector de basura de Python eventualmente recuperará la memoria. Pero esto ocurre automáticamente: tú no controlas cuándo.

Eliminar elementos de colecciones

La sentencia del también puede eliminar elementos de colecciones, pero esto es fundamentalmente diferente de eliminar nombres. Cuando usas del con indexación o slicing de una colección, estás modificando la colección en sí, no eliminando un nombre.

Esta es una distinción importante: cuando escribes del numbers[2], estás llamando a un método especial del objeto lista para eliminar un elemento. El nombre numbers sigue existiendo y sigue refiriéndose al mismo objeto lista: la lista simplemente tiene menos elementos ahora.

python
# Eliminar elementos de una lista por índice
numbers = [10, 20, 30, 40, 50]
del numbers[2]  # Eliminar el elemento en el índice 2
print(numbers)  # Output: [10, 20, 40, 50]
 
# Eliminar slices de una lista
numbers = [10, 20, 30, 40, 50]
del numbers[1:3]  # Eliminar elementos desde el índice 1 hasta 3 (exclusivo)
print(numbers)  # Output: [10, 40, 50]
 
# Eliminar entradas de un diccionario
person = {'name': 'Alice', 'age': 30, 'city': 'Boston'}
del person['age']
print(person)  # Output: {'name': 'Alice', 'city': 'Boston'}
© 2025. Primesoft Co., Ltd.
support@primesoft.ai