Errores frecuentes al programar en Python

En el desarrollo con Python, a pesar de su sintaxis intuitiva, es común enfrentar errores que pueden causar confusión. A continuación, se exploran algunas trampas habituales, agrupadas temáticamente, con ejemplos alternativos y explicaciones detalladas.

  1. Confusión en el ámbito de las variables

Ejemplo problemático:

punto = 8
def obtener_valor():
    print(punto)  # Provoca UnboundLocalError
    punto = 3
obtener_valor()

Causa: Python interpreta las variables asignadas dentro de una función como locales. Si se hace referencia antes de la asignación, se genera un error.

Solución: Emplear declaraciones como global o nonlocal cuando sea necesario, o evitar reasignar variables con el mismo nombre en el contexto local.

  1. Uso de objetos mutables como valores predeterminados

Ejemplo incorrecto:

def insertar_elemento(valor, conjunto=[]):
    conjunto.append(valor)
    return conjunto

print(insertar_elemento(10))  # [10]
print(insertar_elemento(20))  # [10, 20] — Se esperaba [20]

Razón: Los parámetros por defecto se evalúan una sola vez en la definición de la función, compartiéndose entre llamadas posteriores.

Corrección: Utilizar None como valor inicial y crear una nueva lista dentro de la función:

def insertar_elemento(valor, conjunto=None):
    if conjunto is None:
        conjunto = []
    conjunto.append(valor)
    return conjunto
  1. Diferencia entre listas por comprensión y generadores

Error típico:

cuadrados = (n**2 for n in range(4))
print(list(cuadrados))  # [0, 1, 4, 9]
print(list(cuadrados))  # [] — El generador ya se agotó

Motivo: Los generadores son iteradores de un solo uso.

Alternativa: Convertir a lista si se necesita reutilizar los datos, o regenerar el generador cada vez.

  1. Copias superficiales frente a copias profundas

Escenario que causa problemas:

import copy
datos = [[1, 2], [3, 4]]
copia = copy.copy(datos)
copia[0][0] = 50
print(datos)  # [[50, 2], [3, 4]] — La estructura original se modificó

Explicación: Una copia superficial solo duplica el contenedor externo; los objetos internos siguen siendo referencias.

Remedio: Usar copy.deepcopy() para obtener una copia independiente.

  1. Rendimiento en concatenación de cadenas

Ejemplo ineficinete:

acumulador = ""
for fragmento in fragmentos:
    acumulador += str(fragmento)  # Crea nuevos objetos string en cada iteración

Problema: Las cadenas son inmutables, y el operador += genera una nueva cadena en cada paso, impactando el rendimiento.

Mejor práctica: Usar el método ''.join(lista_de_cadenas) para mayor eficiencia.

  1. Manejo inadecuado de excepciones

Antipatrón común:

try:
    operacion_arriesgada()
except:  # Captura cualquier excepción, incluyendo SystemExit o KeyboardInterrupt
    pass

Consecuencia: Bloquear errores específicos y dificultar la interrupción del programa.

Recomendación: Capturar excepciones concretas, como except ValueError:.

  1. Referencias vs. copias en objetos mutables

Error conceptual:

a = [1, 2, 3]
b = a
b.append(4)
print(a)  # [1, 2, 3, 4] — Ambas variables apuntan al mismo objeto

Causa: La asignación b = a crea una referencia, no una copia.

Solución: Generar una copia con b = a.copy() o b = a[:].

  1. Diferencias entre operadores de identidad y valor

Confusión típica:

x = [5, 6]
y = [5, 6]
print(x == y)  # True — Comparación de valores
print(x is y)  # False — No son el mismo objeto en memoria

Nota: == verifica igualdad de valores, mientras que is verifica si son el mismo objeto. No confiar en is para tipos primitivos, ya que Python puede usar caché.

  1. Modificar listas durante su iteración

Problema durante el bucle:

elementos = [1, 2, 3, 4, 5]
for elem in elementos:
    if elem % 2 == 0:
        elementos.remove(elem)  # Salta elementos al modificar durante el recorrido

Corrección: Usar listas por comprensión o iterar en orden inverso:

elementos = [x for x in elementos if x % 2 != 0]
  1. Codificación en operaciones de archivos

Omisión frecuente:

with open('archivo.txt') as fichero:  # Depende del sistema operativo
    contenido = fichero.read()

Riesgo: Errores de decodificación en entornos mixtos o con caracteres especiales.

Práctica segura: Especificar la codificación explícitamente:

with open('archivo.txt', encoding='utf-8') as fichero:
    contenido = fichero.read()
  1. Organización de paquetes con __init__.py

Problema habitual: No crear el archivo __init__.py en directorios de paquetes puede impedir la importación. Aunque Python 3.3+ permite paquetes de espacio de nombres implícitos, es recomendable incluirlo para mayor claridad.

  1. Enlace de variables en funciones lambda dentro de bucles

Ejemplo engañoso:

funciones = [lambda x: x * i for i in range(3)]
print([f(2) for f in funciones])  # [4, 4, 4] — Se esperaba [0, 2, 4]

Razón: La variable i se evalúa al momento de la llamada, no de la definición.

Ajuste: Capturar el valor actual con un parámetro por defecto:

funciones = [lambda x, valor=i: x * valor for i in range(3)]

Para mejorar la calidad del código, se sugiere usar anotaciones de tipo (por ejemplo, def funcion(par: int) -> str:) y herramientas estáticas como pylint o mypy. Además, consultar la documentación oficial y guías de estilo como PEP 8 es fundamental.

Etiquetas: Python ámbito de variables parámetros por defecto generadores copia profunda

Publicado el 6-23 22:41