← Python EspañolChapter 13 of 13

Mejores Prácticas

## Objetivos de Aprendizaje - Escribir código Python limpio y mantenible - Seguir las pautas de estilo PEP 8 - Dominar técnicas de depuración - Escribir pruebas efectivas ## Estilo de Código ### Pautas PEP 8 - Usa 4 espacios por nivel de indentación - Las líneas deben tener ≤ 79 caracteres (límite suave) - Dos líneas en blanco entre definiciones de nivel superior - Una línea en blanco entre definiciones de métodos en una clase - Sin espacios alrededor de `=` para argumentos de palabra clave o valores por defecto ```python # Bien def saludar(nombre, saludo="Hola"): return f"{saludo}, {nombre}!" # Mal def saludar ( nombre, saludo = "Hola" ) : return saludo + ", " + nombre + "!" ``` ### Convenciones de Nomenclatura ```python # Variables y funciones: snake_case nombre_usuario = "Ana" def calcular_total(): pass # Clases: PascalCase class CuentaUsuario: pass # Constantes: UPPER_SNAKE_CASE MAX_REINTENTOS = 3 API_URL = "https://api.ejemplo.com" # Privado: prefijo con guion bajo _funcion_privada() _variable_instancia ``` ### Imports ```python # Biblioteca estándar primero import os import sys # Terceros import requests from flask import Flask # Aplicación local from mipaquete import mimofulo # Absoluto vs Relativo from paquete import modulo # Preferido from . import modulo # OK para relativo import modulo # Evitar relativo ``` ## Funciones ### Responsabilidad Única ```python # Bien - cada función hace una cosa def validar_email(email): """Verificar si el email es válido.""" return "@" in email and "." in email def enviar_email(destinatario, mensaje): """Enviar un email.""" if not validar_email(destinatario): raise ValueError("Email inválido") # Lógica de envío... # Mal - la función hace demasiado def enviar_email(destinatario, mensaje): # Valida, envía, registra, reintenta... ``` ### Retornos Tempranos ```python # Bien - retorno temprano para guard clauses def procesar(usuario): if usuario is None: return None if not usuario.esta_activo: return None return usuario.procesar() # Mal - anidado profundamente def procesar(usuario): if usuario is not None: if usuario.esta_activo: return usuario.procesar() else: return None else: return None ``` ### Docstrings ```python def sumar(a, b): """ Suma dos números. Args: a: Primer número b: Segundo número Returns: La suma de a y b Raises: TypeError: Si a o b no es un número """ if not isinstance(a, (int, float)) or not isinstance(b, (int, float)): raise TypeError("Los argumentos deben ser números") return a + b ``` ## Clases ### Usar Properties ```python # Bien - usar property para acceso controlado class CuentaBancaria: def __init__(self, saldo): self._saldo = saldo @property def saldo(self): return self._saldo @saldo.setter def saldo(self, valor): if valor < 0: raise ValueError("El saldo no puede ser negativo") self._saldo = valor ``` ### dataclasses para Clases Simples ```python from dataclasses import dataclass @dataclass class Punto: x: float y: float def distancia_desde_origen(self): return (self.x ** 2 + self.y ** 2) ** 0.5 ``` ## Manejo de Errores ### Excepciones Específicas ```python # Bien try: valor = int(entrada_usuario) except ValueError: print("Por favor introduce un número válido") # Mal - captura todo try: valor = int(entrada_usuario) except: print("Error") ``` ### Jerarquía de Excepciones ```python # Crear excepciones específicas class ValidationError(Exception): pass class InvalidEmailError(ValidationError): pass class InvalidPasswordError(ValidationError): pass ``` ### No Suprimir Excepciones ```python # Mal try: hacer_algo() except: pass # Bien - al mínimo, registrarla try: hacer_algo() except Exception as e: logging.error(f"Falló: {e}") raise ``` ## Sugerencias de Tipo ```python from typing import List, Dict, Optional, Union def procesar(numeros: List[int]) -> Dict[str, int]: return { "cantidad": len(numeros), "suma": sum(numeros), } def encontrar_usuario(id_usuario: int) -> Optional[str]: if id_usuario == 0: return None return "Usuario encontrado" def parsear(valor: Union[str, int]) -> int: return int(valor) ``` ## Rendimiento ### List Comprehensions sobre Bucles ```python # Bien cuadrados = [x ** 2 for x in range(100)] # Mal cuadrados = [] for x in range(100): cuadrados.append(x ** 2) ``` ### Generadores para Datos Grandes ```python # Bien - eficiente en memoria def leer_archivo_grande(nombre_archivo): with open(nombre_archivo) como f: for linea in f: yield linea # Mal - carga todo el archivo def leer_archivo_grande(nombre_archivo): with open(nombre_archivo) como f: return f.readlines() ``` ### Cacheo de Variables Locales ```python import math # Más lento - búsqueda de atributo repetida def calcular(numeros): resultado = [] for num in numeros: resultado.append(math.sin(num) + math.cos(num)) return resultado # Más rápido - cachear funciones math def calcular(numeros): resultado = [] sin, cos = math.sin, math.cos for num in numeros: resultado.append(sin(num) + cos(num)) return resultado ``` ## Conceptos Básicos de Pruebas ### Usando unittest ```python import unittest class TestMatematica(unittest.TestCase): def test_sumar(self): self.assertEqual(1 + 1, 2) def test_dividir(self): self.assertRaises(ZeroDivisionError, lambda: 1 / 0) if __name__ == "__main__": unittest.main() ``` ### Usando pytest ```python import pytest def test_sumar(): assert 1 + 1 == 2 def test_dividir(): with pytest.raises(ZeroDivisionError): 1 / 0 def test_list_comprehension(): resultado = [x ** 2 for x in range(5)] assert resultado == [0, 1, 4, 9, 16] ``` ## Depuración ### Depuración con print() ```python def funcion_con_error(x): print(f"DEBUG: x = {x}") # Añadir salida de depuración return x * 2 ``` ### assert ```python def procesar(edad): assert edad >= 0, "La edad no puede ser negativa" assert isinstance(edad, int), "La edad debe ser un entero" # Procesar... ``` ### Usando pdb ```python import pdb def funcion_con_error(x): pdb.set_trace() # Punto de interrupción return x * 2 ``` ## Resumen - Seguir las pautas de estilo PEP 8 - Usar nombres de variables y funciones significativos - Mantener funciones pequeñas y enfocadas - Usar sugerencias de tipo para documentación - Manejar excepciones específicamente - Usar list comprehensions sobre bucles - Usar generadores para grandes conjuntos de datos - Escribir pruebas para código crítico - Usar aserciones para depuración - Mantener código DRY (Don't Repeat Yourself)

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →