- Aprender
- Informática
- Programación
- Introducción a la programación con Python
- Módulos y depuración en Python
Módulos y depuración en Python: pruebas y aserciones
math y random, escribe tus propios módulos e instala paquetes de PyPI con pip. Después, lee trazas de excepciones (tracebacks) y mensajes de error, detecta errores de programación (bugs) con un proceso de depuración paso a paso y comprueba tus funciones con sentencias assert y tus primeras pruebas unitarias.PrincipianteUnidad 9 de 10 del curso Curso de Introducción a la programación con Python
Lo que aprenderás
- Incorpora código ya escrito a un programa con sentencias import, usa módulos de la biblioteca estándar como
mathyrandom, divide tu propio código en módulos e instala paquetes de terceros con pip.- Incorpora código a un programa con sentencias importUsa correctamente
import,from … importyas, accede a nombres con la notación de punto y distingue los errores de importación. - Calcula y realiza simulaciones con math, random y otros módulos estándarUsa las funciones principales de
mathyrandom, evita sus errores habituales y conoce algunos otros módulos de uso frecuente de la biblioteca estándar. - Escribe e importa tus propios módulosDivide el código en tus propios archivos
.py, impórtalos, evita conflictos de nombres y usaif __name__ == "__main__":para que un archivo pueda ejecutarse e importarse. - Instala y gestiona paquetes con pipInstala, inspecciona, actualiza y elimina paquetes de terceros de PyPI, impórtalos con el nombre correcto y resuelve los problemas habituales de instalación.
- Incorpora código a un programa con sentencias import
- Usa la salida de error de Python para averiguar dónde ha fallado un programa y por qué, y distingue entre errores de sintaxis, errores de ejecución y errores lógicos.
- Lee una traza de excepción de abajo arribaIdentifica el tipo de excepción, el mensaje, la línea que falla y la cadena de llamadas que ha llevado hasta ella.
- Reconoce errores habituales y sus causasRelaciona los tipos de excepción más frecuentes con sus causas y soluciones habituales, y detecta errores lógicos que no generan mensajes.
- Lee una traza de excepción de abajo arriba
- Localiza la causa de un error de programación con un proceso paso a paso, sin hacer cambios a ciegas, e inspecciona un programa en ejecución con llamadas a print y un depurador.
- Sigue un proceso de depuración paso a pasoReproduce un error de programación, formula y comprueba una hipótesis, acota la causa, corrígela y vuelve a probar.
- Inspecciona un programa con llamadas a print, tablas de seguimiento y un depuradorObserva cómo cambian los valores durante la ejecución del código añadiendo llamadas a print, siguiendo la ejecución a mano o deteniéndola en puntos de interrupción.
- Sigue un proceso de depuración paso a paso
- Usa
assertpara indicar qué debe ser verdadero, escribe pequeñas pruebas automatizadas para tus funciones y ejecútalas e interpreta sus resultados con el módulo estándarunittest.- Comprueba supuestos con sentencias assertEscribe sentencias
assertcon mensajes claros y reconoce cuándo las aserciones son la herramienta adecuada y cuándo no. - Escribe tus primeras pruebas unitarias para tus funcionesEscribe funciones de prueba con aserciones, elige casos típicos, valores límite y casos límite, y utiliza las pruebas que fallan para detectar y corregir errores de programación.
- Organiza y ejecuta pruebas con unittestEscribe pruebas con
unittest.TestCase, ejecútalas e interpreta el informe de pruebas superadas, fallos y errores.
- Comprueba supuestos con sentencias assert
Guía de estudio de Módulos y depuración en Python
1Reutiliza módulos e instala paquetes
El código importado permite que un programa pequeño use cálculos, simulaciones y herramientas escritos en otros lugares. Elegirás una forma de importación, trabajarás con funciones de la biblioteca estándar y organizarás tus propias funciones para que otro archivo pueda reutilizarlas. La instalación añade otra pregunta: ¿qué Python recibe un paquete de terceros? Entender esa relación facilita diagnosticar la ausencia de un módulo y mantener claros los nombres de cada programa.
1.1 Importa un módulo o nombres seleccionados
Un módulo contiene código Python que otro programa puede reutilizar. La mayoría de los módulos son archivos .py. La biblioteca estándar viene con Python; el código de terceros requiere una instalación aparte. Un paquete agrupa módulos relacionados, normalmente en una carpeta.
Haz que la llamada coincida con la importación
Una importación crea nombres en tu programa. La forma que eliges determina cómo llamas al código importado.
| Sentencia | Nombre creado | Ejemplo de llamada |
|---|---|---|
import math | math | math.sqrt(16) |
from math import sqrt | sqrt | sqrt(16) |
import statistics as stats | stats | stats.mean([2, 4, 9]) |
from random import randint as roll | roll | roll(1, 6) |
La notación de punto consiste en buscar un nombre dentro de un módulo u objeto. En math.sqrt(16), Python encuentra sqrt dentro de math y la llama con 16. El resultado es 4.0. La constante math.pi no necesita paréntesis de llamada porque es un valor, no una función.
Después de import math, usar solo sqrt(16) lanza NameError: el programa tiene un nombre para el módulo, pero no un nombre independiente para sqrt. Después de usar únicamente from math import sqrt, el error inverso, math.sqrt(16), también lanza NameError porque math no se ha vinculado. Un alias sustituye el nombre habitual de la vinculación importada: import statistics as stats crea stats, no ambos nombres.
Resuelve el mismo cálculo de dos formas
Un triángulo rectángulo tiene catetos de 3 y 4. Primero eleva al cuadrado los catetos y suma los resultados; después calcula la raíz cuadrada.
import math
length = math.sqrt(3**2 + 4**2)
print(length) # 5.0
La expresión dentro de la llamada se convierte en 9 + 16 y después en 25; sqrt devuelve 5.0. Con from math import sqrt, escribe en su lugar length = sqrt(3**2 + 4**2). Usar el prefijo del módulo permite ver de dónde procede una función y mantiene sus demás nombres fuera del espacio de nombres de tu programa. La propia vinculación math sí puede sustituir una variable anterior llamada math.
Mantén claros los nombres
Evita from math import *. Esta importación con comodín incorpora nombres públicos a tu programa sin nombrarlos individualmente. Por ejemplo, e = 5 seguido de esa importación cambia e a 2.718281828459045. Una importación que parece no tener relación puede, por tanto, cambiar un cálculo posterior. PEP 8 recomienda importaciones explícitas y las coloca al principio, con un módulo por línea: primero la biblioteca estándar, después los paquetes de terceros y, por último, tus propios módulos.
Python ejecuta el código de nivel superior de un módulo en su primera importación durante una ejecución del programa. Las importaciones posteriores reutilizan el módulo cargado; no vuelven a iniciarlo.
Usa el error para elegir la solución
| Error | Qué revisar |
|---|---|
ModuleNotFoundError con import mathh | La escritura del nombre del módulo y su instalación |
ImportError con from math import square_root | El nombre solicitado al módulo |
AttributeError con math.sqroot(16) | El nombre que sigue al punto |
En la consola interactiva, ejecuta import math y después dir(math) para enumerar sus nombres. Ejecuta help(math.sqrt) para leer la documentación de una función. La referencia oficial de la biblioteca de Python explica sus argumentos y su resultado.
Puntos clave
import modulecrea una vinculación con un módulo; accede a su contenido con la notación de punto.from module import namecrea la vinculación seleccionada;aselige un alias.- Las importaciones explícitas mantienen claro el origen de los nombres y reducen las sustituciones accidentales.
- Los errores de importación distinguen entre un módulo no encontrado, un nombre importado no disponible y un atributo ausente.
dir()enumera nombres;help()explica cómo usar uno.
1.2 Elige funciones de math y random
La biblioteca estándar proporciona herramientas probadas para cálculos y simulaciones. Para elegir una función, empieza por el resultado que necesitas: un recuento entero, una medida redondeada, un elemento aleatorio o una lista reordenada.
Redondear tiene varios significados
Después de import math, math.sqrt(16) devuelve el número de coma flotante 4.0. math.pi y math.e proporcionan las constantes 3.141592653589793 y 2.718281828459045. math.factorial(5) multiplica los enteros de 1 a 5 y devuelve 120.
| Expresión | Resultado | Significado |
|---|---|---|
math.floor(7.9) | 7 | Mayor entero que no supera el valor |
math.ceil(2.1) | 3 | Menor entero que no es inferior al valor |
math.floor(-2.5) | -3 | Hacia abajo significa hacia menos infinito |
int(-3.5) | -3 | La conversión trunca hacia cero |
round(2.5) | 2 | Un valor exactamente a mitad de camino se redondea al par |
round(3.5) | 4 | El entero par vecino es 4 |
Para una pared de 23 metros cuadrados y 10 metros cuadrados por lata de pintura, la división da 2.3 latas. Comprar latas enteras requiere math.ceil(23 / 10), que devuelve 3. round(2.3) da 2 y deja una cantidad de pintura insuficiente.
La función incorporada round() no necesita ninguna importación. Para un círculo de radio 2, round(math.pi * 2 ** 2, 2) da 12.57. El redondeo cambia la precisión de un número; es una tarea distinta de comprar suficientes recipientes enteros.
Comprueba dominios y comparaciones de números de coma flotante
math.sqrt(-1) lanza ValueError porque no hay una raíz cuadrada real para esa entrada. Los números de coma flotante calculados también requieren cuidado: su almacenamiento en binario hace que 0.1 + 0.2 == 0.3 sea False. math.isclose(0.1 + 0.2, 0.3) es True; úsalo para comparar de forma aproximada números de coma flotante calculados.
Selecciona la operación aleatoria
El módulo random utiliza un algoritmo para producir resultados pseudoaleatorios.
| Llamada | Resultado |
|---|---|
random.randint(1, 6) | Un entero de 1 a 6, ambos incluidos |
random.randrange(1, 6) | Un entero de 1 a 5 |
random.random() | Un número de coma flotante mayor o igual que 0,0 y menor que 1,0 |
random.uniform(a, b) | Un número de coma flotante entre los extremos indicados |
random.choice(items) | Un elemento |
random.sample(items, k) | Elementos de k posiciones, sin reemplazo |
random.shuffle(items) | Reordena la lista existente; devuelve None |
Mantén random.shuffle(cards) en su propia línea. Asignar su resultado de nuevo a cards pierde la vinculación con la lista al sustituirla por None. Muestrear posiciones también es distinto de exigir valores diferentes: random.sample([1, 1], 2) devuelve [1, 1].
Ejecuta una simulación reproducible
import random
sevens = 0
for _ in range(1000):
if random.randint(1, 6) + random.randint(1, 6) == 7:
sevens += 1
print(sevens)
Seis de los 36 pares equiprobables suman 7, por lo que el recuento suele estar cerca de 167, pero cambia entre ejecuciones. Para reproducir una secuencia durante la depuración, llama a random.seed(42) antes de generar los valores, usando la misma versión de Python y la misma secuencia de llamadas. Para contraseñas o tokens de seguridad, usa secrets.
Encuentra otras herramientas de uso habitual
statistics.mean([2, 4, 9]) devuelve 5; statistics.median([2, 4, 9]) devuelve 4. datetime.date.today() da la fecha de hoy. Después de import sys, sys.argv contiene el nombre del archivo de programa seguido de sus argumentos: ejecutar python greet.py Ada proporciona ['greet.py', 'Ada'].
Puntos clave
floor,ceil,intyroundresuelven distintas necesidades de redondeo.- Usa
math.iscloseal comparar números de coma flotante calculados. randintincluye ambos extremos;randrangeexcluye su límite de parada.sampleselecciona posiciones sin reemplazo, por lo que los valores duplicados de la entrada pueden repetirse.shufflemodifica la lista original y devuelveNone.- Una semilla fija ayuda a reproducir el comportamiento aleatorio; los tokens de seguridad requieren
secrets.
1.3 Haz que un archivo sea reutilizable sin iniciar su programa
Una función es más fácil de reutilizar cuando está en un módulo centrado en una tarea. Otro programa puede importar esa función, y una prueba puede comprobarla sin pedir a una persona que ejecute toda la aplicación.
Separa la función del código que la llama
Guarda este código como geometry.py:
"""Calculations for simple shapes."""
import math
def circle_area(radius):
"""Return the area of a circle with the given radius."""
return math.pi * radius ** 2
En la misma carpeta, guarda este código que realiza la llamada como main.py:
import geometry
print(geometry.circle_area(2))
Ejecuta python main.py. Python encuentra geometry, crea su función y después el código que realiza la llamada ejecuta esa función. El resultado mostrado es 12.566370614359172. Importa sin la terminación .py. Un nombre de módulo válido usa letras, dígitos y guiones bajos con un primer carácter válido; my_tools.py funciona con import my_tools, mientras que import my-tools es sintaxis no válida.
Las cadenas situadas al principio del módulo y de la función son cadenas de documentación. Describen el propósito del código y aparecen en help(geometry) y help(geometry.circle_area).
Comprende qué ejecuta una importación
En la primera importación, Python ejecuta por orden las sentencias de nivel superior del módulo. Una sentencia def crea una función; no ejecuta el cuerpo de esa función. Sin embargo, un print(circle_area(2)) sin condición de protección al final de geometry.py mostraría su salida durante la importación.
Ese efecto secundario importa cuando un módulo contiene solicitudes de datos o un bucle del programa. Una prueba que solo necesita circle_area no debería tener que iniciar el programa y responder a sus solicitudes.
Protege el inicio y mantén disponible la función
Añade esto debajo de la función reutilizable en geometry.py:
def main():
print(circle_area(2))
if __name__ == "__main__":
main()
Python establece __name__ para cada módulo. Una ejecución directa, python geometry.py, lo establece en "__main__", por lo que la condición es verdadera y se llama a main(). Importar geometry lo establece en "geometry", así que Python omite la llamada. Las definiciones situadas antes de la condición de ejecución directa siguen disponibles en ambos casos.
No coloques la propia circle_area dentro de la condición de ejecución directa. El código que importa necesita esa definición incluso cuando la condición de inicio es falsa. La condición controla cuándo se inicia la aplicación; no impide que Python cargue el módulo.
Conoce dónde busca Python
Python comprueba módulos integrados como sys y después las carpetas de sys.path, por orden. Normalmente, la carpeta del archivo de programa en ejecución aparece primero en esa ruta, seguida de las carpetas de la biblioteca estándar y de los paquetes instalados. Mantener tus propios archivos junto al archivo de programa que ejecutas es una organización sencilla para un proyecto de principiante. Una importación normal no puede encontrar un módulo situado fuera de la ruta de búsqueda.
Este orden también puede ocultar un módulo de biblioteca. Si guardas tu programa como random.py, su import random puede cargar tu archivo en lugar de la biblioteca. Una llamada posterior a random.randint(1, 6) lanza entonces AttributeError. Cambia el nombre del archivo, por ejemplo, a dice.py; Python 3.13 y versiones posteriores pueden incluir en el error una sugerencia para cambiar el nombre.
Un módulo cargado se reutiliza dentro de la misma ejecución. En una consola interactiva, editar el archivo y volver a importarlo mantiene la versión cargada. Reinicia la consola antes de probar tus cambios.
Puntos clave
- Importa tu propio archivo
.pyusando su nombre de módulo sin la extensión. - Una importación ejecuta las sentencias de nivel superior, mientras que los cuerpos de las funciones esperan a las llamadas.
- Mantén las definiciones reutilizables fuera de la condición de ejecución directa
__main__y el inicio del programa dentro. - Un archivo local puede ocultar un módulo de biblioteca con el mismo nombre.
- Reinicia la consola interactiva para probar desde cero un módulo editado.
1.4 Instala paquetes para el Python que ejecutas
Los paquetes de terceros añaden código que no viene con Python. PyPI, el Python Package Index en https://pypi.org, aloja estos proyectos. pip los descarga e instala para una instalación concreta de Python.
Usa la terminal y después Python
Un comando de terminal y una sentencia de Python se escriben en lugares distintos. El indicador >>> significa que estás en la consola interactiva de Python. Introducir pip install requests allí genera SyntaxError; Python no puede interpretarlo como una sentencia.
En tu terminal, ejecuta:
python -m pip install cowsay
Después, pon esto en un programa de Python:
import cowsay
cowsay.cow("Hello, Ada")
El programa muestra una vaca hecha con texto junto a un globo de diálogo que contiene el mensaje. La instalación hace que el paquete esté disponible; la importación crea la vinculación del programa con él.
Haz que pip corresponda a tu intérprete
La forma -m pip pide al Python indicado que ejecute su propio pip. Usa el comando que inicia tus programas: a menudo, python3 en macOS o Linux, o py en Windows.
python3 -m pip install cowsay
python3 game.py
Ambas líneas seleccionan el mismo comando de Python. Si una instalación informa de que ha terminado correctamente, pero un archivo de programa sigue lanzando ModuleNotFoundError, compara el Python usado para instalar con el usado para ejecutar el archivo. Un editor puede haber seleccionado un intérprete distinto del de tu terminal. Usa el pip del intérprete seleccionado antes de cambiar la importación.
Inspecciona y mantén una instalación
| Comando de terminal | Tarea |
|---|---|
python -m pip list | Enumerar los paquetes instalados y sus versiones |
python -m pip show requests | Mostrar detalles, incluida su ubicación de instalación |
python -m pip install --upgrade requests | Actualizar a la versión más reciente disponible |
python -m pip install "requests==2.32.3" | Seleccionar esa versión exacta |
python -m pip uninstall requests | Eliminar el paquete |
Una versión exacta resulta útil cuando necesitas el comportamiento de esa versión concreta. show ayuda a comprobar qué ubicación ha modificado realmente pip.
Comprueba el nombre en la documentación
El nombre de distribución escrito para pip puede diferir del nombre de importación. Instala beautifulsoup4 y después usa import bs4; instala Pillow y después usa import PIL. Instalar repetidamente un nombre de importación no es una solución útil cuando la documentación indica otra distribución.
La biblioteca estándar de Python, incluidos math, random y unittest, ya viene con Python. Estos módulos no requieren una instalación con pip.
Respeta una instalación gestionada
Algunos sistemas operativos y gestores de paquetes protegen su Python con un error externally-managed-environment. Esto significa que se bloquea la instalación directa para mantener la coherencia de la instalación gestionada. Usa un entorno virtual, una carpeta independiente con Python y paquetes para el proyecto. No fuerces la instalación con sudo pip install.
Cualquiera puede publicar en PyPI. Antes de instalar, comprueba la escritura exacta del nombre y lee la página y la documentación del proyecto. Los nombres parecidos pueden ser intentos de suplantación mediante nombres similares. Da preferencia a paquetes consolidados que reciban mantenimiento e instala los que tu programa necesita realmente.
Puntos clave
- Ejecuta los comandos de pip en una terminal y las importaciones en el código Python.
- Usa
python -m pipcon el mismo comando de intérprete que ejecuta el programa. - Consulta el nombre de importación en la documentación; puede diferir del nombre de instalación.
- Usa pip para inspeccionar, actualizar, seleccionar una versión o eliminar un paquete.
- Un Python gestionado puede requerir un entorno virtual para el proyecto.
- Comprueba la escritura del nombre del paquete y su documentación antes de instalar código de terceros.
2Lee errores y trazas de excepciones
La salida de error de Python registra tanto la operación que ha fallado como las llamadas que han llegado a ella. Leer esas pistas en orden te ayuda a encontrar un punto de partida útil, en lugar de cambiar la primera línea que reconozcas. Seguirás una traza hasta su entrada, distinguirás tipos habituales de excepción y reconocerás el caso menos evidente en el que un programa se ejecuta con normalidad, pero produce un resultado incorrecto. El comportamiento esperado te da algo concreto que comprobar.
2.1 Sigue una traza de excepción hasta la entrada incorrecta
Una traza de excepción indica qué llamadas estaban activas cuando una excepción no manejada detuvo el programa. Ofrece tanto un lugar por el que empezar a leer como un camino de vuelta hacia el valor que causó el fallo.
Empieza por la última línea
Considera este programa completo en scores.py:
def average(values):
return sum(values) / len(values)
def report(scores):
avg = average(scores)
print(f"Average: {avg:.1f}")
report([])
La última línea de su informe de error es ZeroDivisionError: division by zero. Indica el tipo de excepción y describe la operación que ha fallado. Empieza ahí y después lee hacia arriba hasta la ubicación del código inmediatamente anterior.
Una traza simplificada, sin las marcas de expresión, es:
Traceback (most recent call last):
File "scores.py", line 8, in <module>
report([])
File "scores.py", line 5, in report
avg = average(scores)
File "scores.py", line 2, in average
return sum(values) / len(values)
ZeroDivisionError: division by zero
Lee cada marco como una llamada activa
Un marco de ejecución indica el archivo, el número de línea y la función, seguidos del código correspondiente. in <module> significa código de nivel superior. La llamada más antigua está arriba; la más reciente, abajo. Leer desde abajo invierte ese orden para que puedas averiguar qué ha fallado antes de preguntar cómo ha llegado allí la ejecución.
- La línea 2 divide entre
len(values). Para que ese divisor sea cero,valuesdebe estar vacío. - La línea 5 llama a
average(scores), así que inspecciona elscoresque pasareport. - La línea 8 proporciona
[], la lista vacía. Eso explica cómo ha llegado el divisor cero al cálculo.
La línea que falla y la causa están relacionadas, pero pueden encontrarse en lugares distintos. Sustituir la división sin decidir qué debe significar una lista vacía ocultaría la cuestión de diseño. El código que realiza la llamada debe evitar una lista vacía o la función necesita un comportamiento definido para una entrada vacía.
Usa las marcas sin depender de su forma exacta
Python 3.11 y versiones posteriores pueden añadir marcas ^ y ~ para mostrar la parte de una expresión que falla. Ayudan cuando una línea contiene varias operaciones. Las marcas exactas varían entre versiones, pero las ubicaciones de las llamadas y el mensaje de excepción siguen indicando el orden de lectura.
Una traza puede contener marcos de la biblioteca estándar o de un paquete instalado. Busca el marco más bajo de tu propio código e inspecciona los argumentos que has proporcionado allí. Un marco de biblioteca es una pista de ubicación; no demuestra que la biblioteca contenga el error.
Reconoce un informe de sintaxis
Un error de sintaxis en el archivo de programa que se inicia impide que ese archivo se ejecute. Python informa de un archivo, una línea, una marca y un mensaje sin la cabecera habitual de la traza. Por ejemplo, a if True le faltan los dos puntos; total = sum([1, 2, 3] deja un paréntesis abierto.
El lugar marcado es donde Python ha detectado que no podía analizar el código. Cuando esa línea parece válida, revisa la anterior en busca de una comilla o un paréntesis sin cerrar. No hay una cadena de llamadas en ejecución que seguir cuando el archivo de programa inicial no ha llegado a ejecutarse.
Una ejecución normal se detiene en su primera excepción no manejada. Corrige ese problema y vuelve a ejecutar para descubrir cualquier problema posterior del programa.
Puntos clave
- Lee primero el tipo de excepción y el mensaje, después el marco que falla y las llamadas que lo han originado.
- Los marcos van desde la llamada activa más antigua, arriba, hasta la más reciente, abajo.
- Sigue el valor incorrecto hacia atrás; su origen puede ser anterior al fallo.
- Un error de sintaxis en el archivo de programa inicial se comunica antes de que ese archivo se ejecute.
2.2 Distingue entre un nombre, un tipo, un valor y un resultado incorrectos
El nombre de un error acota la búsqueda, y su mensaje añade detalles sobre los valores implicados. Un programa también puede ser incorrecto sin lanzar una excepción, por lo que comprobar la salida esperada sigue siendo parte de la detección de errores.
Distingue tres tipos de problema
| Tipo | Qué ocurre | Ejemplo |
|---|---|---|
| Error de sintaxis | Python no puede analizar el código | Faltan dos puntos después de if |
| Error de ejecución | La ejecución llega a una operación no válida | Dividir entre cero |
| Error lógico | La ejecución termina con un comportamiento incorrecto | Un bucle omite un precio |
IndentationError es un tipo de SyntaxError. El cuerpo de una función necesita sangría; la ausencia de un bloque con sangría detiene el código antes de que se ejecute. Revisa también las comillas o los paréntesis sin cerrar y las palabras reservadas mal escritas.
Lee con atención los nombres y los tipos
Un NameError significa que el programa no conoce un nombre en ese punto. En prnt("hi"), la función incorporada que se pretendía usar es print. También puede haberse usado un nombre antes de asignarle un valor o puede faltar una importación.
Un TypeError significa que una operación ha recibido un tipo inadecuado o que una llamada ha recibido un número incorrecto de argumentos. "Age: " + 30 mezcla una cadena y un entero. Escribe "Age: " + str(30) o f"Age: {30}". Si area necesita w y h, area(3) también genera TypeError, esta vez porque falta un argumento.
El mensaje distingue estas causas. En can only concatenate str (not "int") to str, Python indica los tipos que se han combinado. Después de age = input("Age: "), age es texto. age + 1 falla; para una entrada que representa un entero, int(age) + 1 realiza una operación aritmética.
Un ValueError significa que se acepta el tipo de la entrada, pero su valor no es adecuado. int("12.5") recibe una cadena, que es un tipo de entrada aceptado, pero el texto no representa un número entero con la forma requerida. math.sqrt(-1) es otro valor inadecuado para un cálculo con números reales.
Comprueba posiciones, claves y atributos
| Excepción | Ejemplo | Causa |
|---|---|---|
IndexError | [4, 6, 10][3] | El último índice válido es 2 |
KeyError | {"apples": 3}["pears"] | El diccionario no tiene "pears" |
ZeroDivisionError | 10 / 0 | El divisor es cero |
AttributeError | math.sqroot(16) | El módulo no tiene sqroot |
ModuleNotFoundError | import mathh | No se encuentra ningún módulo con ese nombre |
ImportError | from math import square_root | El módulo no tiene ese nombre importado |
Los divisores cero también provocan fallos con // y %. Buscar una posición inexistente en una lista es distinto de buscar una clave inexistente en un diccionario, aunque ambos casos impliquen solicitar algo que no está.
Detecta un resultado que parece razonable
def total_price(prices):
total = 0
for i in range(1, len(prices)):
total += prices[i]
return total
Para [4, 6, 10], esto devuelve 16 en lugar de 20. No hay ninguna excepción: los índices 1 y 2 existen, así que todas las operaciones son válidas. El bucle empieza demasiado tarde y omite el índice 0. El error se hace visible al comparar la salida con el total previsto.
Para una excepción que no conozcas, busca su tipo y el mensaje general en la documentación oficial de Python. Elimina de la búsqueda tus propias rutas y valores de entrada; rara vez explican la regla general.
Puntos clave
- Los errores de sintaxis impiden analizar el código; los de ejecución ocurren al ejecutarlo; los lógicos producen un comportamiento incorrecto.
NameErrorse refiere a una vinculación;TypeError, a un tipo o a los argumentos de una llamada.ValueErrorse refiere a un valor inadecuado proporcionado con un tipo aceptado.IndexError,KeyErroryAttributeErrorse refieren a distintos tipos de consulta.- Comparar la salida con un resultado esperado puede revelar un error lógico sin traza de excepción.
3Encuentra la causa de un error de programación
Un resultado incorrecto es más fácil de investigar cuando puedes reproducirlo y decir exactamente en qué difiere del resultado esperado. Convertirás esa observación en una suposición comprobable, acotarás la búsqueda a un pequeño fragmento de código e inspeccionarás los valores relevantes. Las llamadas a print, las tablas de seguimiento y los controles del depurador ofrecen distintas formas de observar la ejecución. Después de una corrección concreta, comprobar los casos que antes funcionaban ayuda a detectar cualquier comportamiento afectado por el cambio.
3.1 Comprueba una causa antes de cambiar el código
Un error de programación es una diferencia entre el comportamiento previsto y el real. La depuración encuentra la causa y la corrige. Una sesión de depuración útil convierte una observación en una explicación comprobable y después modifica el código basándose en pruebas.
Haz que el fallo se repita
Registra una entrada concreta y el resultado que produce. Para la función de precios que empieza su bucle en el índice 1, usa [4, 6, 10]. El total esperado es 20; el total real es 16. Estos valores concretos permiten comprobar si cada investigación sigue tratando el mismo error.
La diferencia es 4, y el resultado real equivale a 6 + 10. Una hipótesis concreta es que se omite el primer precio. Esa hipótesis predice algo que puedes inspeccionar: el bucle nunca visitará el índice 0.
Sigue seis pasos
- Reproduce: encuentra una entrada que muestre el error de forma fiable.
- Indica los resultados esperado y real: calcula el resultado esperado de forma independiente.
- Formula una hipótesis: indica una causa posible y el comportamiento que predice.
- Compruébala: inspecciona los valores con llamadas a print, una tabla de seguimiento o un depurador.
- Corrige la causa: realiza un cambio concreto.
- Vuelve a probar: ejecuta la entrada que fallaba y los casos que antes funcionaban.
Muestra el índice dentro del bucle. Para esta entrada, los únicos índices son 1 y 2, lo que confirma la predicción. Iniciar range en 0 corrige la omisión del elemento. Recorrer directamente los precios elimina la necesidad de gestionar un índice:
def total_price(prices):
total = 0
for price in prices:
total += price
return total
La función corregida devuelve 20 para [4, 6, 10], 5 para [5] y 0 para []. El caso de un elemento es útil porque el bucle con el error devolvía antes 0 para él.
Sumar 4 a todas las respuestas corregiría el total observado, pero dejaría la causa. Para [5], ese parche devolvería 4; la cantidad que falta depende de la entrada. Comprueba si una solución propuesta explica todas las pruebas observadas antes de conservarla.
Acota una búsqueda más amplia
Divide y vencerás comprueba los valores que intervienen en el resultado incorrecto en un punto intermedio de la ejecución. Si un valor necesario ya es incorrecto, inspecciona el código anterior que lo ha producido. Si los valores necesarios siguen siendo correctos, sigue su procesamiento posterior. Repite el proceso dentro de la sección restante.
También puedes llamar a una función por separado o eliminar temporalmente código no relacionado. Un ejemplo mínimo reproducible conserva el código más breve y la entrada más pequeña que siguen fallando. Para un problema detectado inicialmente entre cientos de registros, encontrar uno o dos registros que lo desencadenen facilita cada inspección.
Comprueba qué son realmente los datos
Un 5 mostrado puede ser la cadena "5". "5" + "3" produce "53", mientras que la suma numérica da 8. Inspecciona type(value) para comprobar el tipo. Usa repr(value) para revelar espacios y caracteres de salto de línea que una salida normal puede ocultar, como ' Ada'.
Explica el código en voz alta, línea por línea, incluido qué visita realmente cada bucle y qué devuelve cada función. Esto es la depuración con un patito de goma: explicar un paso suele revelar la diferencia entre la operación prevista y la escrita.
Cambia una causa cada vez para poder relacionar el resultado con la modificación. Vuelve a probar tanto los casos que antes funcionaban como el que fallaba.
Puntos clave
- Reproduce el error y registra los resultados esperado y real antes de editar.
- Una hipótesis útil predice algo que puedes inspeccionar.
- Corrige la causa con un cambio y después vuelve a probar los casos que fallaban y los que antes funcionaban.
- Usa un ejemplo mínimo o valores intermedios para acotar la búsqueda.
- Comprueba los tipos y los caracteres ocultos cuando el aspecto de los valores resulte engañoso.
3.2 Observa cómo cambian los valores con llamadas a print y un depurador
La respuesta final de un programa oculta el camino que la ha producido. Las llamadas temporales a print, una tabla de seguimiento y un depurador permiten ver ese camino y comprobar una hipótesis concreta sobre dónde falla.
Muestra un valor en un momento conocido
Etiqueta la salida de diagnóstico para que un número tenga un significado claro. Python 3.8 y versiones posteriores admiten esta forma de cadena formateada:
print(f"{i=} {total=}")
Para el bucle de precios con el error, colócala inmediatamente antes de total += prices[i]. Con los precios [4, 6, 10], muestra:
i=1 total=0
i=2 total=6
Estos son los totales antes de cada suma. Después de la primera salida, el bucle suma 6; después de la segunda, suma 10. Una llamada a print después de la suma mostraría totales distintos. Decide qué momento responde a lo que quieres averiguar antes de interpretar la salida.
Sigue el mismo código a mano
Una tabla de seguimiento registra las variables paso a paso. Para este bucle:
Índice i | Precio sumado | Total antes | Total después |
|---|---|---|---|
| 1 | 6 | 0 | 6 |
| 2 | 10 | 6 | 16 |
No hay ninguna iteración para el índice 0. Sigue los valores reales de inicio y parada escritos en el código, incluso cuando ya sepas qué debería hacer el bucle. Una tabla ayuda a separar lo que esperas de lo que ocurre.
Pausa en un punto de interrupción
Un depurador pausa un programa en ejecución para que puedas inspeccionar su estado actual. Un punto de interrupción marca un lugar donde detenerse. En editores como Thonny y VS Code, haz clic junto a un número de línea e inicia el modo de depuración; en IDLE, haz clic derecho en la línea y elige Establecer punto de interrupción.
Después de pausar, elige un paso según lo que estés investigando:
| Control | Efecto |
|---|---|
| Paso a paso por procedimientos | Ejecutar la línea actual, incluida una función llamada |
| Paso a paso por instrucciones | Entrar en una función llamada en esa línea |
| Salir de la función | Terminar esta función y pausar después del retorno |
| Continuar | Ejecutar hasta otro punto de interrupción o el final del programa |
Si el código que realiza la llamada pasa argumentos correctos, pero recibe una respuesta incorrecta, entra en la función. Si solo necesitas ver el resultado devuelto, ejecuta la llamada como un solo paso. Inspecciona los valores antes y después de la línea que podría crear el error.
Usa el depurador de texto de Python
Inserta breakpoint() justo antes del código que quieras inspeccionar. Con la configuración predeterminada del depurador, ejecutar el programa inicia pdb en ese punto. Escribe estos comandos en su indicador (Pdb):
p totalmuestratotal.nejecuta la siguiente línea sin entrar en sus llamadas.sentra en una llamada a función.ccontinúa la ejecución.qsale de la sesión de depuración.
Son comandos del depurador, no líneas para copiar en tu programa.
Distingue la salida mostrada de los resultados devueltos
Una función puede mostrar el número correcto y aun así devolver None porque le falta return total. Inspecciona el valor recibido por el código que realiza la llamada cuando el fallo ocurre después de llamar a la función. Ver una salida correcta dentro de la función no demuestra que el código que la llama haya recibido ese número.
Usa llamadas a print para obtener pistas rápidas a lo largo de las iteraciones de un bucle y el depurador para inspeccionar un momento concreto. Después de corregir el error, elimina las llamadas temporales a print y a breakpoint() para que el programa terminado se ejecute con normalidad.
Puntos clave
- Etiqueta las salidas de depuración e indica si se ejecutan antes o después de una actualización.
- Una tabla de seguimiento sigue los cambios reales de las variables paso a paso.
- Los puntos de interrupción pausan la ejecución; los controles de avance determinan cuánto código se ejecuta a continuación.
breakpoint()abre pdb de forma predeterminada;p,n,s,cyqson comandos del depurador.- Inspecciona los valores devueltos cuando una función muestra la salida correcta, pero el código que la llama falla.
- Elimina la salida de diagnóstico temporal y los puntos de interrupción después de corregir el error.
4Comprueba tus funciones con pruebas
Las comprobaciones automatizadas permiten repetir un ejemplo útil cada vez que cambia una función. Escribirás aserciones con expectativas claras, elegirás entradas que alcancen los límites de una regla y evitarás que las pruebas inicien la aplicación que importan. Después, el marco estándar unittest da a cada prueba un nombre y un resultado independiente. Leer sus fallos y errores conecta las pruebas con la depuración: la prueba reproduce un problema y la investigación encuentra su causa.
4.1 Escribe comprobaciones que fallen cuando un supuesto sea falso
Una aserción expresa algo que debe ser verdadero si tu código funciona correctamente. Puede detener un error cerca de donde empieza o comparar el resultado de una función con el valor que esperas.
Escribe una condición y un mensaje opcional
assert letter_grade(90) == "A", "90 should be an A"
Python evalúa la condición. Si letter_grade(90) devuelve "A", la condición es verdadera y la ejecución continúa sin salida. Si devuelve "B", Python lanza AssertionError con el mensaje 90 should be an A. La traza señala la comprobación que falla.
Sin el mensaje, assert letter_grade(90) == "A" sigue comprobando el resultado. La última línea de la excepción contiene AssertionError, mientras que la traza muestra la expresión. Un mensaje útil indica la expectativa que no se ha cumplido; debe ayudarte a localizar la regla que se comprueba.
Detén pronto un error interno
Supón que un cálculo interno requiere una lista no vacía:
def average(values):
assert len(values) > 0, "values must not be empty"
return sum(values) / len(values)
Una lista vacía activa ahora la aserción antes de la división. La comprobación documenta el supuesto interno de la función y señala directamente su incumplimiento. No da una media a una lista vacía ni decide cómo debe responder una aplicación cuando faltan datos de un usuario.
Mantén activa la validación de datos del usuario
La opción -O de Python elimina las sentencias assert. Por tanto, un programa que dependa de una aserción para rechazar una entrada externa puede comportarse de forma distinta al optimizarse. Comprueba los datos del usuario y otros datos externos con el flujo de control habitual:
def require_score(score):
if score < 0 or score > 100:
raise ValueError("score must be 0 to 100")
return score
Aquí raise ValueError(...) comunica un valor inadecuado. La sentencia if sigue ejecutándose con -O. Elige una aserción para un supuesto interno de programación y una comprobación de entrada activa para datos externos que puedan ser incorrectos.
Evita una comprobación que nunca pueda fallar
assert es una sentencia, no una función. Escribe la condición y el mensaje separados por una coma:
assert x > 10, "x too small"
Escribir assert (x > 10, "x too small") crea una tupla de dos elementos. Una tupla no vacía es verdadera incluso cuando su primer elemento es False, por lo que la aserción se cumple. Python puede avisar de que esta aserción siempre es verdadera. Los paréntesis que rodean solo una condición, como en assert (x > 10), no crean esa tupla; el problema es la coma dentro de los paréntesis.
Usa == para comparar. assert total = 20 es sintaxis no válida porque = asigna un valor.
Compara números con la precisión prevista
Para un número de coma flotante calculado, usa una comprobación de proximidad:
import math
assert math.isclose(0.1 + 0.2, 0.3)
Una comparación exacta falla aquí porque la suma almacenada en coma flotante difiere ligeramente de 0.3. Una prueba automatizada sencilla aplica la misma idea de aserción a una función: assert total_price([4, 6, 10]) == 20. El valor esperado procede de la regla de la función, por lo que la comprobación puede revelar una implementación incorrecta.
Puntos clave
assert condition, messagelanzaAssertionErrorcuando su condición es falsa.- Las aserciones pueden comprobar supuestos internos y resultados esperados de funciones.
- Usa
ify un mensaje de error o una excepción para la entrada externa;-Oelimina las aserciones. - Una coma dentro de
assert (condition, message)crea una tupla considerada verdadera. - Usa
==para la igualdad ymath.isclosepara comparar números de coma flotante calculados.
4.2 Elige pruebas que puedan revelar un error de programación
Una prueba unitaria comprueba una pequeña unidad de código, normalmente una función, con una entrada elegida y un resultado esperado. Las pruebas automatizadas facilitan repetir las mismas comprobaciones después de editar el código y ayudan a detectar errores que reaparecen en comportamientos que antes funcionaban.
Empieza por la especificación
Supón que una función de calificación debe devolver "A" para puntuaciones de al menos 90, "B" para puntuaciones de al menos 80 pero inferiores a 90, y "C" por debajo de 80. La primera condición, que contiene el error, es score > 90.
Las pruebas deben cumplir varias funciones:
- Los casos típicos comprueban entradas habituales dentro de cada tramo, como 95 y 85.
- Los casos en los límites comprueban los valores donde cambia una regla, como 90 y 89, u 80 y 79.
- Los casos límite comprueban entradas como cero o una colección vacía cuando las reglas de la función las permiten.
Calcula la respuesta esperada a partir de esas reglas. Copiar la respuesta actual del programa en una prueba puede conservar su error.
Coloca las pruebas junto al módulo
Guarda las pruebas en test_grade.py y la función en grade.py. El inicio de la aplicación en grade.py debe estar dentro de su condición de ejecución directa __main__, para que importar la función no inicie el programa.
from grade import letter_grade
def test_letter_grade():
assert letter_grade(95) == "A"
assert letter_grade(90) == "A"
assert letter_grade(85) == "B"
Con la regla que contiene el error, la primera aserción se cumple. La segunda falla porque 90 no es mayor que 90; la ejecución se detiene ahí, antes de la tercera aserción de esta función. Cambiar la primera condición a score >= 90 corrige este límite. Vuelve a ejecutar todas las pruebas para comprobar el caso afectado y el comportamiento anterior.
Asegúrate de que las pruebas se ejecuten realmente
Definir una función de prueba no la llama. Si no usas un ejecutor de pruebas, añade test_letter_grade() al final del archivo de pruebas y después ejecuta python test_grade.py. Para usar pytest, instálalo con python -m pip install pytest y después ejecuta pytest test_grade.py en la terminal. Encuentra las funciones de prueba e informa de sus resultados. Omite las llamadas manuales cuando dejes que un ejecutor las gestione.
Una prueba que solo llama a letter_grade(90) no incluye ninguna comparación. Puede terminar correctamente aunque la respuesta devuelta sea incorrecta; solo falla si la llamada lanza una excepción inesperada. Una aserción conecta la llamada con el comportamiento requerido.
Prueba valores devueltos y propiedades de resultados aleatorios
Una función que solo muestra un total devuelve None. Por tanto, una comparación como assert print_total([4, 6]) == 10 falla aunque la pantalla muestre 10. Haz que el cálculo devuelva su respuesta y deja que main se encargue de mostrarla.
Los resultados aleatorios necesitan una expectativa distinta. No se puede exigir que una función de dado sin semilla devuelva una cara exacta en cada llamada. Comprueba que cada una de 100 llamadas devuelva un valor permitido de 1 a 6, o establece una semilla antes de generar una secuencia reproducible. Superar la prueba de límites comprueba los límites para esas llamadas; no demuestra que todas las caras sean igual de probables.
Cuando aparezca un error nuevo, añade una prueba que falle por ese error antes de corregir la función. Conserva esa prueba de regresión para que las modificaciones posteriores vuelvan a comprobar el mismo comportamiento. Las pruebas que pasan demuestran lo que ha ocurrido en los casos probados; otras entradas aún pueden revelar otro error.
Puntos clave
- Elige los resultados esperados a partir de la especificación, con independencia de la implementación.
- Prueba entradas habituales, límites de las reglas y casos límite relevantes.
- Las funciones de prueba necesitan una llamada o un ejecutor; las definiciones por sí solas no realizan comprobaciones.
- Las aserciones deben comparar los resultados devueltos con el comportamiento previsto.
- Prueba propiedades adecuadas de la salida aleatoria o prepara una secuencia reproducible.
- Conserva una prueba para cada error nuevo que encuentres para ayudar a detectar regresiones.
4.3 Ejecuta e interpreta un archivo de pruebas de unittest
Python incluye unittest, un marco de pruebas que detecta pruebas, las ejecuta e informa de sus resultados por separado. No necesita instalación con pip. Puedes usar su estructura de clases como plantilla mientras aprendes a probar funciones.
Escribe métodos de prueba independientes
Para una función de grade.py, coloca esto en test_grade.py:
import unittest
from grade import letter_grade
class TestLetterGrade(unittest.TestCase):
def test_top(self):
self.assertEqual(letter_grade(95), "A")
def test_boundary(self):
self.assertEqual(letter_grade(90), "A")
def test_low(self):
self.assertEqual(letter_grade(50), "C")
if __name__ == "__main__":
unittest.main()
TestLetterGrade hereda las herramientas de prueba de unittest.TestCase. Cada prueba es un método cuyo nombre empieza por test. self identifica el objeto de prueba actual; mantenlo en la lista de parámetros de cada método y antes de las llamadas a métodos de aserción. Puedes copiar esta estructura sin diseñar tus propias clases.
De forma predeterminada, las pruebas se ejecutan por orden alfabético de sus nombres de método, así que test_boundary va antes de test_low y test_top. Haz que cada prueba proporcione su propia entrada necesaria y funcione con independencia de las pruebas anteriores.
Elige un método de aserción
| Método | Comprobación |
|---|---|
self.assertEqual(actual, expected) | Los valores son iguales |
self.assertNotEqual(a, b) | Los valores son distintos |
self.assertTrue(condition) | Una condición es verdadera |
self.assertFalse(condition) | Una condición es falsa |
self.assertIn(item, collection) | El elemento pertenece a la colección |
self.assertAlmostEqual(a, b) | La diferencia redondeada a 7 decimales es cero, de forma predeterminada |
Da preferencia a assertEqual(a, b) frente a assertTrue(a == b) al comparar valores: el informe de fallo muestra ambos valores. Los métodos de unittest también mantienen sus comprobaciones cuando Python se ejecuta con -O.
Para comprobar una excepción esperada, encierra la llamada en assertRaises:
def test_score_too_high(self):
with self.assertRaises(ValueError):
letter_grade(120)
Esta prueba exige que la regla de la función rechace esa puntuación con ValueError. Un retorno sin excepción hace fallar esta comprobación; una excepción distinta que no sea de aserción se considera un error.
Ejecuta y lee el informe
Ejecuta python test_grade.py para ejecutar su unittest.main() protegido por la condición de ejecución directa. O ejecuta python -m unittest para detectar archivos test*.py en la carpeta actual. python -m unittest -v muestra los nombres de las pruebas y sus resultados individuales.
En el informe breve, . significa que la prueba pasa, F que una aserción ha fallado y E que se ha producido otra excepción. Para una función de calificación con score > 90, las tres pruebas anteriores producen F... El informe de fallo de test_boundary muestra 'B' != 'A': el resultado real es "B", mientras que el esperado es "A". El resumen indica tres pruebas y un fallo.
Antes de editar la función, contrasta la expectativa de la prueba con las reglas de calificación. Una expectativa incorrecta requiere corregir la prueba. Si no se ejecuta ninguna prueba, revisa los nombres de los métodos, la condición de ejecución directa y el comando de inicio. Evita también llamar a tu archivo unittest.py, ya que oculta el módulo estándar.
Puntos clave
- Coloca métodos
testdentro de una clase que herede deunittest.TestCase. - Usa
self.assertEqualy otros métodos de aserción para obtener comprobaciones e informes claros. assertRaisescomprueba una excepción esperada; las comparaciones de números de coma flotante pueden usarassertAlmostEqual.- Ejecuta directamente un archivo de pruebas protegido por una condición de ejecución directa o usa
python -m unittestpara detectar pruebas. - Interpreta
Fcomo una aserción fallida yEcomo otra excepción. - Contrasta una prueba fallida con la especificación antes de cambiar la función.
- Cada prueba debe funcionar con independencia del orden alfabético de ejecución.
Ejemplos de Módulos y depuración en Python
1Construye un programa con piezas reutilizables
20 pasos
- 1IntroducciónEmpieza con código que puedas reutilizar
Un programa puede llamar a código de la biblioteca estándar de Python, de otro archivo que hayas escrito o de un paquete instalado. La primera cuestión es qué nombre tiene disponible el programa después de importar.
Seguirás un cálculo desde una importación hasta su valor devuelto y después organizarás un módulo reutilizable y vincularás la instalación de un paquete con su intérprete. Durante el proceso, comprueba si un resultado es un valor que conservas o un cambio realizado en una lista existente.
- 2ExplicaciónLa importación determina la forma de la llamada
Estas importaciones permiten acceder a la misma función mediante vinculaciones distintas:
import math print(math.sqrt(16))from math import sqrt print(sqrt(16))Ambas muestran
4.0. La primera creamath, así que la llamada usa un punto. La segunda creasqrt, por lo que no necesita prefijo de módulo. Usar la forma de llamada incorrecta lanzaNameErrorcuando ese nombre no se ha vinculado. - 3EjemploCalcula la hipotenusa
Con
import math, para un triángulo rectángulo con catetos de 3 y 4 puedes usar:length = math.sqrt(3**2 + 4**2)Los cuadrados son 9 y 16. Su suma es 25 y
math.sqrt(25)devuelve5.0. Python evalúa el argumento antes de llamar a la función.El prefijo también indica a quien lee el código de dónde procede
sqrt. Una importación con comodín oculta ese origen y puede sustituir nombres existentes, como una variable llamadae. - 4DesafíoSigue la vinculación del alias
Un archivo de programa recién iniciado ejecuta estas líneas. ¿Qué ocurre en la última línea y cómo se puede corregir?
import statistics as st print(statistics.mean([4, 8, 12]))---reveal---
Lanza
NameErrorporque la importación vinculast, nostatistics. Usast.mean([4, 8, 12]), que devuelve8. Un alias elige la vinculación en este programa; no crea además el nombre original del módulo. - 5EjemploRedondea para obtener suficientes recipientes enteros
Una pared necesita pintura para 23 metros cuadrados. Cada lata cubre 10 metros cuadrados.
import math cans = math.ceil(23 / 10)La división da
2.3;ceilda3, suficientes latas enteras.round(2.3)solo da2.Para entradas negativas, hacia abajo sigue significando hacia menos infinito:
math.floor(-2.5)es-3, mientras queint(-2.5)trunca hacia cero y da-2. - 6Idea claveAdapta la comparación al número
Los números de coma flotante calculados pueden diferir ligeramente de los valores decimales que se pretenden obtener:
0.1 + 0.2 == 0.3 # False math.isclose(0.1 + 0.2, 0.3) # TrueUsa una comprobación de proximidad para esa comparación aproximada. Además, las entradas permitidas por una función siguen siendo relevantes:
math.sqrt(-1)lanzaValueError.La función incorporada
roundno necesita ninguna importación. Para un valor exactamente a mitad de camino, elige el vecino par:round(2.5)es2yround(3.5)es4. - 7ExplicaciónElige el resultado aleatorio que necesitas
Después de
import random, elige una llamada según su tarea:randint(1, 6)elige un entero e incluye el 6.randrange(1, 6)elige un entero y excluye el 6.random()da un número de coma flotante desde 0,0 hasta 1,0, sin incluirlo.choice(items)elige un elemento.sample(items, k)eligekposiciones sin reemplazo.
Dos posiciones seleccionadas pueden contener el mismo valor. Por tanto, muestrear
[1, 1]en ambas posiciones da valores 1 repetidos. - 8DesafíoConserva la lista mezclada
¿Qué valor contiene
namesal final y cómo debe cambiar la última línea para conservar la lista?names = ["Mina", "Luis", "Jo"] names = random.shuffle(names)---reveal---
Contiene
None.shufflemodifica la lista existente y después devuelveNone; la asignación sustituye la vinculación con la lista por ese valor de retorno. Usarandom.shuffle(names)en su propia línea. El nuevo orden de la lista es aleatorio, pero lo que devuelve la función es fijo. - 9ConexiónRepite una simulación y encuentra otras herramientas
Llama a
random.seed(42)antes de generar valores para repetir la misma secuencia con la misma versión de Python. Así resulta más fácil reproducir un fallo aleatorio. Usasecretspara tokens de seguridad.Otros módulos estándar resuelven tareas habituales:
statistics.mean([2, 4, 9])da5ymedianda4.datetime.date.today()da la fecha de hoy.sys.argvenumera el nombre del archivo de programa en ejecución seguido de sus argumentos de línea de comandos. - 10EjemploColoca una función reutilizable en un módulo
Guarda esto como
geometry.py:import math def circle_area(radius): """Return the circle's area.""" return math.pi * radius ** 2Un archivo de programa de la misma carpeta puede ejecutar
import geometryy despuésprint(geometry.circle_area(2)). Muestra12.566370614359172.Importa el archivo sin
.py. La primera cadena de la función es su cadena de documentación, quehelp(geometry.circle_area)puede mostrar. - 11ExplicaciónUna importación ejecuta las sentencias de nivel superior
Supón que
geometry.pytermina conprint(circle_area(2)), fuera de una función. Su primera importación muestra el área como efecto secundario.Python ejecuta las sentencias del nivel del módulo por orden. Definir
circle_areacrea la función sin ejecutar su cuerpo; llamarla dentro de la llamada a print de nivel superior ejecuta el cálculo. Una segunda importación en el mismo proceso reutiliza el módulo cargado. Una consola interactiva también conserva esa versión cargada después de editar el archivo, hasta que la reinicies. - 12EjemploInicia el programa solo en una ejecución directa
Deja la función reutilizable encima de este bloque:
def main(): print(circle_area(2)) if __name__ == "__main__": main()Una ejecución directa establece
__name__en"__main__", así que se ejecutamain(). Una importación lo establece en"geometry", así que se omite el inicio.Las definiciones siguen disponibles en ambos casos. Esto permite que una prueba importe
circle_areasin producir la salida habitual del programa. - 13DesafíoMantén la función disponible para el código que la importa
Un archivo define
convertdentro de su bloqueif __name__ == "__main__":. Un proceso de pruebas recién iniciado importa el archivo y no encuentraconvert. ¿Qué organización permite tanto reutilizar la función como iniciar el programa en una ejecución directa?---reveal---
Mueve
def convert(...)fuera de la condición de ejecución directa y deja solo el inicio del programa dentro. Durante la importación, la condición es falsa, así que se omite una definición situada dentro. Mover la definición hace que esté disponible sin iniciar la aplicación. - 14ConsejoComprueba qué archivo encuentra una importación
Python comprueba los módulos integrados y después busca en
sys.pathpor orden. La carpeta del archivo de programa suele aparecer antes que las carpetas de bibliotecas. Por tanto, unrandom.pylocal puede ocultar elrandomque querías importar.Cambia el nombre de ese archivo a algo como
dice.py. Para tus propias funciones auxiliares, usa nombres válidos comomy_tools.pyy mantenlas junto al archivo de programa de principiante que las importa. Una importación normal no encuentra un archivo situado fuera de la ruta de búsqueda. - 15EjemploInstala en la terminal e importa en Python
En la terminal, ejecuta:
python -m pip install cowsayDespués, el código Python puede usar:
import cowsay cowsay.cow("Hello, Ada")El paquete muestra una vaca hecha con texto y un globo de diálogo.
pipinstala código, mientras queimportcrea la vinculación que usa tu programa. El comando de instalación no es una sentencia de Python; en un indicador>>>produce sintaxis no válida. - 16ExplicaciónUsa el pip que pertenece al Python en ejecución
Si un archivo de programa se ejecuta con
python3, instala mediante el mismo comando:python3 -m pip install cowsay python3 game.py-m pipselecciona el pip que pertenece a ese intérprete. En Windows, tu comando puede serpy.Si el editor no puede importar un paquete instalado correctamente, compara su intérprete seleccionado con el usado en la terminal. Instalar correctamente en un Python no instala el paquete en todos los demás Python.
- 17DesafíoDistingue el nombre de instalación del nombre de importación
La documentación de un paquete indica que debes instalar
Pillowe importarPIL. La instalación se completa correctamente para el Python que ejecutas, peroimport Pillowfalla. ¿Qué debe cambiar y por qué?---reveal---
Usa
import PIL. El nombre de distribución que usa pip puede diferir del nombre de importación de Python que proporciona. Como ya se ha comprobado que el intérprete coincide, repetir el mismo comando de instalación dejaría sin corregir este error concreto de nombre. - 18ConsejoInspecciona un paquete antes de modificarlo
python -m pip listmuestra las versiones instaladas.show requestsda la versión y la ubicación de un paquete;install --upgrade requestslo actualiza yuninstall requestslo elimina. Cada comando abreviado va después depython -m pip.Comprueba el nombre exacto en PyPI y la documentación del proyecto antes de instalar. Ante un error
externally-managed-environment, usa un entorno virtual para el proyecto; no fuerces la instalación consudo pip install. - 19DesafíoPredice una importación y una llamada posterior
Un módulo nuevo
sizes.pycontiene este código. Otro archivo de programa ejecutafrom sizes import batchesy despuésprint(batches(17)). ¿Qué se muestra?import math def batches(n): return math.ceil(n / 5) if __name__ == "__main__": print(batches(12))---reveal---
Solo se muestra
4. La importación crea la función, pero omite la llamada a print protegida por la condición. La llamada posterior divide 17 entre 5 y después redondea 3,4 hacia arriba a 4. La vinculaciónmathdentro desizesestá disponible para su función. - 20RepasoSigue el código desde su origen hasta la llamada
Elige una importación que coincida con los nombres que quieres usar. Comprueba qué devuelve una llamada de biblioteca, incluido un posible
Nonede una operación que modifica una lista.Mantén las definiciones reutilizables disponibles durante la importación y coloca el inicio de la aplicación dentro de la condición de ejecución directa. Para el código instalado, haz que pip corresponda al intérprete en ejecución y comprueba el nombre de importación documentado. Cuando falla una llamada, estos detalles ayudan a distinguir una vinculación ausente, un atributo ausente y una instalación ausente.
2Sigue un fallo hasta su causa
11 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónUsa el informe como prueba
- 2EjemploUna lista vacía llega a una división
- 3ExplicaciónEncuentra el marco más reciente
- 4EjemploSigue el argumento hacia atrás a través de las llamadas
- 5DesafíoLocaliza un argumento inadecuado
- 6ExplicaciónDistingue gramática, tipos y valores
- 7ExplicaciónDistintas consultas generan distintos errores
- 8EjemploUn total incorrecto puede terminar con normalidad
- 9DesafíoExplica una suma fallida
- 10DesafíoUsa un marco de biblioteca sin culpar a la biblioteca
- 11RepasoElige el siguiente lugar que revisar
3Investiga un error desde las pruebas hasta la corrección
14 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónHaz que se repita el resultado incorrecto
- 2EjemploIndica los resultados esperado y real
- 3ExplicaciónHaz que la suposición sea comprobable
- 4EjemploMuestra los valores antes de actualizar
- 5EjemploSigue las sumas a mano
- 6DesafíoInterpreta una salida posterior a la actualización
- 7EjemploCorrige la propia iteración
- 8ConexiónVuelve a probar entradas con distintas estructuras
- 9ConsejoReduce un caso de fallo más amplio
- 10DesafíoComprueba un valor que parece numérico
- 11ExplicaciónPausa en la llamada que necesitas inspeccionar
- 12DesafíoElige el comando de avance
- 13DesafíoInvestiga una salida correcta y un retorno incorrecto
- 14RepasoMantén la corrección vinculada a las pruebas observadas
4Convierte un error en un límite en una prueba permanente
16 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDa al comportamiento esperado una comprobación repetible
- 2ExplicaciónUna aserción expresa una expectativa
- 3DesafíoEncuentra una comprobación que no puede fallar
- 4Idea claveMantén activas las comprobaciones de entradas externas
- 5EjemploElige entradas alrededor del cambio de calificación
- 6EjemploEscribe una función de prueba que importe el código
- 7ConsejoEjecuta las comprobaciones que has definido
- 8DesafíoCorrige un umbral y conserva la comprobación
- 9ConexiónPrueba el resultado devuelto o una propiedad válida
- 10EjemploUsa la plantilla de clase de unittest
- 11ExplicaciónElige la aserción según el resultado
- 12EjemploLee una comprobación de calificación fallida
- 13DesafíoDistingue un fallo de un error
- 14ConsejoComprueba qué ha ejecutado realmente la detección de pruebas
- 15DesafíoUsa un informe para planificar la corrección
- 16RepasoConserva una prueba del comportamiento que has corregido
Ejercicios de Módulos y depuración en Python
Set 1: Importaciones, pistas de errores y primeras comprobaciones10 Preguntas de Práctica
Pregunta 1 de 10
import math antes de su cálculo. ¿Cómo debe llamar a la función de raíz cuadrada con 81?Mostrar respuestaOcultar respuesta
math, así que se accede a la función mediante math.sqrt(81), que devuelve 9.0. Llamar solo a sqrt(81) lanzaría NameError porque esta importación no ha creado una vinculación independiente para sqrt.Pregunta 2 de 10
math.ceil(35 / 8) y qué representa?Mostrar respuestaOcultar respuesta
4.375, así que cuatro vehículos dejan a tres personas sin asiento. ceil redondea hacia arriba al siguiente entero y da cinco vehículos. Redondear al entero más cercano daría cuatro en este caso, pero se necesitan suficientes vehículos enteros para todos.Pregunta 3 de 10
text_tools.py define shorten. ¿Cómo puede otro archivo de la misma carpeta importarla y llamarla?Mostrar respuestaOcultar respuesta
.py, así que import text_tools crea la vinculación con el módulo. La notación de punto permite después acceder a su función shorten. Incluir .py en la importación trata esa terminación como parte de una ruta de importación en lugar de como una extensión de archivo.Pregunta 4 de 10
>>> de Python e introduces pip install cowsay. ¿Por qué informa Python de sintaxis no válida?Mostrar respuestaOcultar respuesta
>>> acepta sentencias de Python, mientras que la sintaxis de instalación de pip es un comando de terminal. Sal de la consola de Python y ejecuta python -m pip install cowsay en la terminal. Importar primero no puede hacer que esté disponible un paquete que aún no está instalado.Pregunta 5 de 10
ZeroDivisionError. Sus marcos, de arriba abajo, muestran show([]), mean(data) y sum(values) / len(values). ¿Qué cadena explica mejor el fallo?Mostrar respuestaOcultar respuesta
len(values), y las llamadas anteriores permiten seguir ese valor hasta la lista vacía. Su longitud es cero, lo que causa la excepción. Un numerador cero está permitido cuando el divisor no es cero, así que la suma por sí sola no explica este fallo.Pregunta 6 de 10
int("7.25")?Mostrar respuestaOcultar respuesta
int, pero "7.25" no es texto con la forma de número entero que requiere esta conversión. Eso provoca ValueError. Un TypeError indicaría un tipo de entrada o una operación inadecuados, no este valor de cadena inadecuado.Pregunta 7 de 10
[9, 2, 5] y obtener 16, pero devuelve 7. Sospechas que omite el primer elemento. ¿Qué observación comprobaría esa idea de forma más directa?Mostrar respuestaOcultar respuesta
Pregunta 8 de 10
¿Qué dos líneas se muestran?
total = 0
for n in [3, 8]:
print(f"{n=} {total=}")
total += n
Mostrar respuestaOcultar respuesta
Pregunta 9 de 10
¿Qué ocurre cuando este código se ejecuta normalmente?
count = 6
assert count < 5, "too many"
print("saved")
Mostrar respuestaOcultar respuesta
6 < 5 es falsa, así que la aserción lanza AssertionError con el mensaje proporcionado. La ejecución se detiene antes de la llamada final a print porque la excepción no se maneja. El mensaje forma parte de la excepción; no es una salida normal tras la que continúa la ejecución.Pregunta 10 de 10
La regla indica gratuidad hasta un peso de 12 incluido, una tarifa de 4 de 13 a 18 y una tarifa de 7 por encima de 18. Las pruebas con 5 y 20 pasan. ¿Qué resultados y modificación diagnostican correctamente este código?
def fee(weight):
if weight < 12:
return 0
if weight <= 18:
return 4
return 7
Mostrar respuestaOcultar respuesta
Set 2: Módulos, decisiones de depuración y resultados de pruebas10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
import statistics as st, la siguiente línea es statistics.mean([3, 7]). No hay otras importaciones ni asignaciones. ¿Qué explica el error?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
¿Cuál es el valor de tickets después de este código?
import random
tickets = [11, 22, 33]
tickets = random.shuffle(tickets)
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
double y después contiene la línea sin protección print(double(6)). Otro archivo de programa lo importa dos veces en una ejecución. ¿Cuántas veces muestra la salida esa línea?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
python -m pip show cowsay indica una ubicación en Python B y el editor no puede importar cowsay. ¿Qué debes hacer primero?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Esta función debería sumar todas las cantidades. ¿Qué tipo de problema explica el resultado de total([2, 5, 8])?
def total(values):
result = 0
for i in range(1, len(values)):
result += values[i]
return result
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
assert (score >= 0, "negative score"). Se cumple cuando score es -3. ¿Qué cambio corrige la comprobación y mantiene activa la validación con -O?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
test_discount, que contiene dos aserciones, pero nunca la llama. Ejecutas ese archivo con python test_discount.py; no hay código de un ejecutor de pruebas. ¿Por qué no se comprueba ninguna aserción?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
self.assertEqual(lookup("x"), 7). La llamada a lookup lanza un KeyError inesperado antes de devolver un valor. ¿Qué resultado breve marca esta prueba?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 3: Sigue las causas a través de módulos y pruebas10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
¿Qué muestra este código?
from math import sqrt as root
sqrt = 4
result = root(sqrt ** 2)
print(result, sqrt)
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
random.sample(["blue", "blue", "red"], 2). ¿Por qué puede contener el resultado dos valores "blue"?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
Un módulo contiene este código. Un proceso recién iniciado lo importa y después llama a helper.answer(). ¿Qué ocurre?
# helper.py
if __name__ == "__main__":
def answer():
return 42
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
run_report(), después muestra tu llamada a parse(raw) y termina dentro de una conversión de biblioteca con ValueError. Inspeccionas raw en tu llamada a parse y encuentras "9x", aunque la regla exige texto que represente un entero. ¿Por dónde debe continuar la investigación?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
result + 2, donde result es el valor de retorno de la llamada. ¿Por qué se produce TypeError?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
answer = calculate(7). Quieres inspeccionar la primera línea dentro de calculate. ¿Qué control debes usar?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
charge(6) devuelve 3, pero su prueba espera 3 y pasa. ¿Qué cambio crea una prueba de regresión útil y corrige la aplicación de la regla?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
test_alpha, que espera 4 pero recibe 5, test_beta, que pasa, y test_gamma, que lanza un TypeError inesperado. ¿Qué cadena compacta de progreso produce la ejecución alfabética predeterminada?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
unittest.TestCase tiene check_empty, con una comprobación de igualdad que falla, y test_full, con una que pasa. El ejecutor informa de una prueba y OK. ¿Cómo debes hacer que se ejecute la comprobación de comportamiento que falta?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 4: Combina decisiones de importación, depuración y pruebas10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
random.randint(2, 5) 50 veces. Una prueba nueva establece la misma semilla con la misma versión de Python y repite las mismas llamadas. ¿Qué deben esperar sus comprobaciones?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
beautifulsoup4 como distribución y bs4 como su módulo. Un archivo de programa importa bs4 correctamente. Un compañero quiere cambiar python -m pip install beautifulsoup4 para instalar bs4 y que los nombres coincidan. ¿Es hacer coincidir esos nombres una razón válida para ese cambio?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
display.py informa de estas llamadas, de arriba abajo: start(" "), read_count(text) y después int(text), y termina en ValueError. ¿Qué secuencia comprueba mejor la causa probable antes de corregirla?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
[6, 3, 2]. ¿Qué resultados esperados y reales para dos entradas nuevas revelan el problema restante?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Esta función muestra un producto correcto, pero el código que la llama recibe TypeError en area(4, 5) + 1. ¿Dónde debes inspeccionar y qué resultado explica el fallo?
def area(w, h):
product = w * h
print(product)
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
¿Qué ocurre en una ejecución normal, sin optimización?
import math
assert math.isclose(0.1 + 0.2, 0.3)
assert 0.1 + 0.2 == 0.3
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
pick() devuelve un entero aleatorio de 3 a 7, ambos extremos incluidos. pair_total() suma dos llamadas a pick(). Una prueba que exige que cada total sin semilla sea igual a 10 falla a veces, aunque ambas funciones funcionan correctamente. ¿Qué comprobación por resultado coincide con el rango de totales requerido?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
reserve(n) debe aceptar cantidades enteras de 0 a 8 incluidos y lanzar ValueError fuera de ese rango. Las pruebas con assertRaises(ValueError) informan de F para -1 porque no se produce ninguna excepción y de E para 9 porque se produce TypeError. Una prueba con 2 pasa. ¿Qué comportamiento debe proporcionar la corrección?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
random.py e importa random, y después falla porque falta random.randint. ¿Qué primer cambio resuelve el conflicto de nombres?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
assert total == 10 para un cálculo interno y assert age >= 0 para datos del usuario. Se ejecuta con -O, con total igual a 9 y age igual a -1. ¿Qué ocurre con esas comprobaciones y qué cambio mantiene la validación de entrada requerida?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Alias
as para un módulo u objeto importado; la importación vincula ese nombre en el programa que importa.stats de import statistics as stats permite al archivo de programa llamar a stats.mean([1, 3, 8]).Aserción
AssertionError cuando es falsa.assert count == 3 comprueba un resultado interno frente a la cantidad que esperas de forma independiente.AssertionError
"wrong total" dirige la atención hacia la prueba que ha comparado el total calculado.B
Biblioteca estándar
math para cálculos y random para simulaciones, como lanzar dados.C
Cadena de documentación
help().circle_area puede explicar el argumento del radio y el área devuelta al código que la llama.Cadena de llamadas
report a una función average muestra cómo una lista ha llegado a la función que divide entre su longitud.Caso límite
Caso límite
Código de nivel superior
print puede producir salida durante la importación aunque el código que importa no llame a ninguna función.Condición de ejecución directa
if __name__ == "__main__": que ejecuta su cuerpo en una ejecución directa y lo omite durante una importación normal.main() permite que las pruebas importen las funciones del módulo sin iniciar su aplicación.D
Depuración
Depuración mediante salidas de diagnóstico
print(f"{i=} {total=}") etiqueta el índice del bucle y el total en el momento inspeccionado.Depurador
calculate para inspeccionar sus argumentos cuando el código que la llama recibe una respuesta incorrecta.Detección automática de pruebas
test*.py de unittest.python -m unittest puede ejecutar los archivos coincidentes sin enumerar cada uno en un comando.Distribución
beautifulsoup4 se instala con ese nombre, pero su documentación indica que se debe importar bs4 en Python.Divide y vencerás
E
Ejemplo mínimo reproducible
Error de ejecución
Error de programación
Error de prueba
E puede producirse cuando una función lanza TypeError antes de que la comprobación de igualdad reciba un valor.Error de sintaxis
if ready puede corregirse añadiendo los dos puntos necesarios antes de su bloque con sangría.Error lógico
Especificación
Excepción
average antes de que el código que la llama muestre la media calculada.F
Fallo de prueba
F puede mostrar que la función ha devuelto "B" donde la regla comprobada exigía "A".H
Hipótesis
I
Importación con comodín
* para incorporar los nombres públicos de un módulo al programa actual, lo que puede ocultar su origen y sustituir vinculaciones existentes.from math import * puede sustituir una variable llamada e por la constante matemática.ImportError
from solicita un nombre que no está disponible en un módulo, aunque Python haya encontrado el propio módulo.from math import square_root señala el nombre solicitado, no una instalación ausente.IndexError
names[4] sugiere comprobar la longitud de la lista y los límites del bucle que han producido 4.Intérprete
K
KeyError
"price" puede revelar que el diccionario actual nunca ha recibido la entrada de precio esperada.M
Marco de ejecución
Método de prueba
test, lo que permite a unittest detectar y ejecutar sus comprobaciones.test_limit puede comprobar un límite por separado de la prueba de una entrada habitual.Módulo
.py, cuyas funciones y variables pueden importarse para usarlas en otro programa.math proporciona sqrt, de modo que un programa puede calcular raíces cuadradas sin definir esa función.Muestreo sin reemplazo
["A", "A", "B"] puede seleccionar ambas posiciones que contienen "A".N
NameError
sqrt después de usar solo import math significa que la función necesita ahí el prefijo math..Notación de punto
math.sqrt(25) encuentra la función sqrt dentro del módulo math ya importado.Número pseudoaleatorio
random.randint(1, 6) puede representar el resultado de un dado en la simulación de un juego de mesa.O
Ocultación de módulos
random.py local puede dejar a un programa sin la función randint de la biblioteca.Opción de optimización
-O cambia la ejecución de Python al eliminar las sentencias assert, por lo que la validación obligatoria no puede depender de ellas.Operación sobre el objeto original (in-place)
random.shuffle(cards) modifica cards y devuelve None, así que no necesita asignación.P
Paquete
Parte entera inferior (suelo)
math.floor redondea hacia menos infinito cuando es necesario.math.floor(-3.2) difiere de la conversión con int(-3.2).Parte entera superior (techo)
math.ceil realiza este redondeo hacia arriba a un entero.Paso a paso por instrucciones
result = convert(text) cuando el valor devuelto sea incorrecto y el texto de entrada parezca correcto.Paso a paso por procedimientos
pip
python3 -m pip show cowsay pide al pip asociado a python3 que muestre los detalles de instalación de ese paquete.Prueba unitaria
Punto de interrupción
PyPI
R
Regresión
Ruta de búsqueda de módulos
sys.path que Python comprueba después de sus módulos integrados al buscar importaciones.ModuleNotFoundError cuando el programa lo importa.S
Semilla
Suplantación mediante nombres similares
T
Tabla de seguimiento
TestCase
unittest.TestCase puede llamar a self.assertEqual dentro de sus métodos de prueba con nombre.Traza de la excepción
TypeError
"Score: " + 8 identifica una cadena y un entero que no pueden unirse mediante esa expresión.V
Validación de datos de entrada
if score < 0 sigue activa cuando Python se ejecuta con las aserciones eliminadas.ValueError
int("6.2") significa que la cadena no representa un entero con la forma requerida.Sobre esta unidad
Crea tus propios Materiales de Estudio
Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.