Saltar al contenido principal
InicioTutorialesPython

Tqdm Python: Una guía con ejemplos prácticos

tqdm es una biblioteca de Python que proporciona una barra de progreso rápida y extensible para bucles e iterables, facilitando la visualización del progreso de tu código.
Actualizado 13 sept 2024  · 11 min leer

¿Te has encontrado alguna vez en una situación en la que un guión de Python de larga duración te hacía preguntarte si pasaba algo detrás de la pantalla?

La incertidumbre sobre el progreso puede llevarte a cancelar una ejecución casi completa o a esperar interminablemente una ejecución de script ya interrumpida.

La página tqdm Python aborda este problema proporcionando indicadores de progreso para tus scripts.

ejemplo de barra de progreso tqdm

¿Qué es tqdm?

Tqdm es una biblioteca de Python que proporciona barras de progreso rápidas y extensibles para bucles e iterables. Es una forma sencilla de seguir el avance de las tareas que requieren mucho tiempo.

El nombre de la biblioteca significa "progreso" en árabe (taqadum, تقدّم), y es una abreviatura de "te quiero demasiado" en español (te quiero demasiado).

Tdqm realiza un seguimiento del progreso y actualiza la visualización de la barra de progreso contando las iteraciones, calculando el tiempo transcurrido y el tiempo restante, y visualizando el progreso global en el relleno de la barra.

Utiliza algoritmos inteligentes para predecir el tiempo restante, y omite las visualizaciones de iteración innecesarias para minimizar la sobrecarga. Utilizar tqdm ofrece varias ventajas, entre ellas

  • Retroalimentación visual: Las barras de progreso permiten a los usuarios ver qué parte de una tarea se ha completado y estimar cuánto tiempo puede llevar la parte restante.
  • Funciona en todas partes: La biblioteca tqdm funciona en cualquier plataforma (Linux, Windows, Mac, FreeBSD, NetBSD, SunOS), en cualquier consola o en una GUI.
  • Fácil integración: Tqdm se integra perfectamente con los cuadernos Jupyter, bibliotecas comunes como Pandasy construcciones comunes de Python como los bucles.
  • Personalización: Ofrece varias opciones para adaptar el aspecto y el comportamiento de las barras de progreso, en las que entraremos más adelante.
  • Rendimiento: Mientras que paquetes similares como ProgressBar tienen una sobrecarga de 800ns/iteración, la sobrecarga de tdqm de 60ns/iteración funciona mucho más rápido.

Conviértete en Ingeniero de Datos

Desarrolla tus habilidades en Python para convertirte en un ingeniero de datos profesional.

Empieza Gratis

Cómo instalar Tqdm 

Como para la mayoría de las bibliotecas de Python, la forma más sencilla de instalar tqdm es utilizar el gestor de paquetes pip.

pip install tqdm

Tqdm: Ejemplo sencillo

Para crear una barra de progreso, envolvemos nuestro iterable con la función tqdm() (que importamos del módulo tqdm ). Veamos un ejemplo sencillo. La función time.sleep(0.01) sirve como marcador de posición para el código que se supone que se ejecuta en cada iteración.

from tqdm import tqdm
    for i in tqdm(range(1000)):
    time.sleep(0.01)
    # …

gif que muestra la finalización de la barra de progreso del código de ejemplo en 10 segundos.

Como atajo para tdqm(range(n)) también puedes utilizar trange(n). El código siguiente devolverá exactamente el mismo resultado que el anterior:

from tqdm import tqdm
    for i in trange(1000):
	time.sleep(0.01)
	# …

Ambos ejemplos devolverán una barra de progreso parecida a la anterior.

Fíjate bien en la barra de progreso para ver qué información proporciona. Desglosemos los detalles presentados por tqdm:

  • Indicadores de progreso:
    • Porcentaje de iteraciones
    • Relleno de barra
    • Fracción de iteraciones totales
  • Métricas:
    • Tiempo transcurrido
    • Tiempo estimado restante
    • Rendimiento (iteraciones por segundo)

Personalización Tqdm: Progresar con tus propias barras

Tqdm ofrece varias opciones de personalización para adaptar el aspecto y el comportamiento de las barras de progreso. Echaremos un vistazo a los parámetros de personalización más importantes antes de examinar casos de uso más avanzados de tqdm.

Añadir una descripción de la barra de progreso

Una personalización común es añadir una etiqueta descriptiva utilizando el parámetro desc, lo que hace que la barra de progreso sea más informativa y ayuda a mantener una visión general sobre los diferentes iterables.

Por ejemplo, si añades el parámetro desc=”Processing large range”, aparecerá el título "Procesando rango grande" a la izquierda de la barra de progreso.

for _ in tqdm(range(20000000), desc="Processing large range"):
	continue

Te animo a que ejecutes el código anterior en tu entorno con y sin el parámetro desc y notes las diferencias.

Especificar el número total de iteraciones

El parámetro total especifica el número total de iteraciones del bucle, lo que permite a tqdm proporcionar estimaciones más precisas del tiempo restante y del porcentaje de finalización.

En un ejemplo básico que utilice tqdm(range()) o trange() esto no es necesario, puesto que el número de iteraciones ya está incluido en los corchetes. Sin embargo, hay dos situaciones principales en las que puede ser útil añadir el parámetro total=n (siendo n el número total): 

1. Iterables sin método len(): Para iterables sin método len(), como generadores con un número desconocido de elementos, tienes que proporcionar el valor total manualmente. Sin este parámetro, tqdm() sólo mostrará el recuento de iteraciones completadas. Ten en cuenta que la barra de progreso comienza de nuevo, si el número real de elementos supera el número total especificado.

from tqdm import tqdm
import time
import random
 
# Function generating random number between 1 and 100
def generate_random_numbers():
	while True:
	        yield random.randint(1, 100)
 
# Without total: tqdm() only shows number of iterations, does not know total
for num in tqdm(generate_random_numbers(), desc=’Random Iteration’):
	time.sleep(0.01)
	# …

Este gif muestra el recuento de iteraciones sin barra de progreso.

Este es el aspecto que tiene si se desconoce el número de artículos y no especificamos el total.

# With total (assuming you know the desired number of iterations): tqdm() shows progress
num_iterations = 1000
for num in tqdm(generate_random_numbers(), total=num_iterations, desc="Random Iteration"):
	time.sleep(0.01)
	# …

En este gif, la barra de progreso vuelve a ser visible, una vez especificado el parámetro total.

Mucho mejor, ¡ahora se muestra la barra de progreso!

2. Actualizaciones manuales: Si estamos actualizando la barra de progreso manualmente dentro de una función utilizando el método update(), es necesario especificar el valor total para garantizar un seguimiento correcto del progreso. El método update() permite, por ejemplo, responder a procesos que cambian dinámicamente o realizar un seguimiento personalizado del progreso. Ya hablaremos de ello más adelante.

Ajustar el aspecto visual

Si queremos ajustar el orden de colocación en el que aparecen los elementos de la barra de progreso, podemos establecer el parámetro bar_format a la cadena de formato preferida. De esta forma, podemos controlar la colocación de varios elementos como el porcentaje, el tiempo transcurrido y el carácter de relleno de la barra. Para más detalles, puedes consultar la documentación.

Otro ajuste del aspecto visual puede hacerse utilizando el parámetro colour. Es posible utilizar cadenas de palabras como "verde" o cadenas de código hexadecimal como "#00ff00".

El parámetro leave se refiere más a la desaparición que a la aparición: determina si la barra de progreso permanece visible o no tras su finalización. Si se establece en True, la barra persistirá después de que termine el bucle; si se establece en False, desaparecerá.

Veamos las diferencias visuales de los resultados en otro ejemplo. El código siguiente crea tres barras de progreso: una con la configuración por defecto, otra en la que se cambian el orden y el color de los elementos, y otra que se configura para que desaparezca una vez completada. Los resultados son visibles en el GIF siguiente.

from tqdm import tqdm
import time
 
# Progress bar 1: Default settings
for i in tqdm(range(300)):
	time.sleep(0.01)
 
# Progress bar 2: Customized bar format and color
for i in tqdm(range(300), bar_format='[{elapsed}<{remaining}] {n_fmt}/{total_fmt} | {l_bar}{bar} {rate_fmt}{postfix}', colour='yellow'):
	time.sleep(0.01)
 
# Progress bar 3: Customized bar format and color, leave=False
for i in tqdm(range(300), bar_format='[{elapsed}<{remaining}] {n_fmt}/{total_fmt} | {l_bar}{bar} {rate_fmt}{postfix}', colour='red', leave=False):
	time.sleep(0.01)

Un gif que muestra tres barras de progreso diferentes: 1) Barra de progreso básica con la configuración por defecto, 2) barra de progreso amarilla con el tiempo transcurrido y el tiempo estimado a la izquierda del porcentaje de finalización y de la barra de progreso, 3) versión roja de la segunda barra que desaparece tras la finalización.

Uso avanzado: Manejo de escenarios más complejos

Ahora que sabemos cómo construir una barra de progreso sencilla y cómo personalizarla, podemos pasar a algunos casos más avanzados.

Barras de progreso anidadas

Los bucles anidados son bucles que están contenidos dentro de otros bucles. En consecuencia, las barras de progreso anidadas son una serie de barras de progreso para cada iteración de bucles contenidos dentro de otros bucles. Para crearlos, envuelve cada bucle con una función tqdm() y añade etiquetas descriptivas para cada iterable. 

El código siguiente tiene tres bucles anidados y es capaz de dar un ejemplo de cómo aparecerán las barras de progreso anidadas:

from tqdm import trange
import time
 
for i in trange(3, desc='outer loop'):
	for j in trange(2, desc='middle loop'):
   		for k in trange(6, desc='inner loop'):
	time.sleep(0.01)

Captura de pantalla que muestra tres barras de progreso anidadas en un cuaderno Jupyter. La barra de progreso más exterior sigue el bucle exterior, la barra de progreso intermedia sigue el bucle intermedio y la barra de progreso más interior sigue el bucle interior. Cada barra de progreso muestra su iteración actual, el total de iteraciones, el tiempo restante estimado y una barra de porcentaje de finalización. El orden de las barras es el descrito en el texto.

En la salida final anterior, podemos reconocer un patrón en el que se actualizan las distintas barras de progreso. Tqdm empezará siempre por el bucle más externo hasta llegar al más interno, cuyas iteraciones se procesarán y la barra de progreso se actualizará en consecuencia.

Supongamos que tenemos tres bucles anidados, como en el ejemplo. Tras la iteración interna inicial, pasará al bucle central, lo actualizará como si tuviera una iteración completa, antes de volver al iterable interno. Este proceso se repite hasta que el bucle central se marca como completo, lo que hará que aparezca la barra exterior con una iteración completa.

Lo mismo ocurre entre el bucle exterior y el central. Al final, la última iteración interna completa la iterable media, que a su vez completa la última iteración externa.

Actualizaciones manuales

Actualizar manualmente las barras de progreso con tqdm puede ser útil en varios escenarios:

  • Iterables de longitud desconocida: Cuando trabajamos con iterables que no tienen una longitud definida (por ejemplo, generadores, flujos de red), podemos actualizar manualmente la barra de progreso en función de la cantidad de datos procesados o del número de operaciones completadas.
  • Procesos dinámicamente cambiantes: Si el número de iteraciones o el tiempo de procesamiento por iteración pueden cambiar durante la ejecución, las actualizaciones manuales nos permiten ajustar la barra de progreso en consecuencia.
  • Seguimiento personalizado del progreso: Para tener un control más granular sobre la barra de progreso, podemos actualizarla manualmente en función de criterios o eventos específicos. Por ejemplo, podríamos querer actualizar la barra de progreso en función de la finalización de determinados hitos o del progreso de tareas individuales dentro de un proceso mayor.
  • Integración con sistemas externos: Si estamos integrando tqdm con sistemas o bibliotecas externas que no proporcionan una forma natural de seguir el progreso, se pueden utilizar actualizaciones manuales para sincronizar la barra de progreso con el proceso externo.

Para actualizar manualmente una barra de progreso tqdm, es importante que el parámetro total se especifique como la estimación del número máximo esperado de iteraciones. Luego, a medida que el código procesa cada nuevo elemento, la barra de progreso debe actualizarse utilizando el método update(). El valor de actualización debe representar el número de iteraciones procesadas desde la última actualización.

Supongamos que esperamos que nuestro iterable contenga hasta 750 elementos. En este ejemplo, la longitud real es un número aleatorio entre 100 y 1000, que desconocemos. Iniciamos la progress_bar, fijando estimated_total en 750. Luego iteramos a través de los datos, actualizando la barra de progreso después de procesar cada punto.

from tqdm import tqdm
def process_data(data):
	time.sleep(0.01)        	# simulate processing data
	processed_data = data
	return processed_data
# Generate an iterable with random length between 100 and 1,000
random_length = random.randint(100, 1000)
data_list = [i for i in range(random_length)]
# Define estimated maximum number of iterations
estimated_total = 750 
# Define the progress bar using the estimated_total
progress_bar = tqdm(total=estimated_total)
# Iterating through data list of unknown length
for data in data_list:
	processed_data = process_data(data)
	progress_bar.update(1)

En este gif, la barra de progreso se completa al 100% (750/750), y luego sigue contando las iteraciones restantes (950 al final).

Subestimamos la longitud del iterable, haciendo que la salida siguiera contando iteraciones después de alcanzar el 100% de progreso.

Multiprocesamiento

El multiprocesamiento y los hilos son técnicas utilizadas para ejecutar tareas de forma concurrente, mejorando el rendimiento y la capacidad de respuesta. En estos escenarios, puede resultar difícil seguir el progreso de las tareas individuales o el progreso global de la ejecución paralela. Tqdm puede ser una herramienta valiosa para proporcionar información visual y controlar el progreso de estas operaciones concurrentes.

El módulo tqdm.contrib.concurrent proporciona funciones especializadas para crear barras de progreso en contextos de multiprocesamiento o roscado. Estas funciones se encargan de la sincronización y comunicación entre el proceso principal y los procesos o hilos trabajadores, garantizando que la barra de progreso se actualice correctamente. Están diseñados para funcionar perfectamente con la API concurrent.futures, utilizando la función ProcessPoolExecutor() o ThreadPoolExecutor().

Aquí tienes un ejemplo que utiliza el módulo tqdm.contrib.concurrent.futures:

import concurrent.futures
from tqdm.contrib.concurrent import process_map
 
def process_data(data):
	for i in tqdm(range(100), desc=f"Processing {data['name']}"):
	    	# Process data
	    	time.sleep(0.01)
 
if __name__ == '__main__':
	with concurrent.futures.ProcessPoolExecutor() as executor:
	    	results = process_map(process_data, [
	        	{'name': 'dataset1'},
	        	{'name': 'dataset2'},
	# …
	])

En este ejemplo, la función process_data() incluye una barra de progreso tqdm para seguir su evolución. La función process_data() se ejecutará simultáneamente para cada dato de la lista. Esto significa que se mostrarán varias barras de progreso simultáneamente, cada una representando el progreso de un proceso distinto. El parámetro desc está configurado para crear dinámicamente una descripción para cada barra de progreso basada en el nombre del conjunto de datos correspondiente, lo que nos ayuda a distinguir entre las distintas barras de progreso.

Integración con pandas

El módulo tqdm.pandas proporciona una forma cómoda de añadir barras de progreso a las operaciones de pandas. Esto es especialmente útil para operaciones que requieren mucho tiempo en grandes MarcosDeDatosya que proporciona información visual sobre el progreso de la tarea. Podemos aplicar el decorador tqdm.pandas() a cualquier función de pandas que opere sobre filas o columnas.

Para empezar, definimos un DataFrame aleatorio con 100.000 filas y llamamos al decorador tqdm.pandas(). Si queremos personalizar la barra de progreso, ahora es el momento de hacerlo, ya que las funciones progress_apply() y progress_map() no toman los parámetros tqdm(). Aquí queremos dar un nombre a las siguientes barras de progreso, por lo que también especificamos el parámetro desc.

import pandas as pd
import numpy as np
from tqdm import tqdm
 
df = pd.DataFrame(np.random.randint(0, 10, (100000, 6)))
 
tqdm.pandas(desc='DataFrame Operation')

Ahora podemos aplicar funciones a filas, columnas o a todo el DataFrame. En lugar de utilizar una de las funciones apply() o map(), llama a progress_apply() o progress_map(), y se mostrará la barra de progreso. Recuerda que apply() y progress_apply() pueden aplicarse a DataFrames, filas o columnas, mientras que map() y progress_map() sólo pueden aplicarse a Series o columnas. Por ejemplo:

# Halving each value in the DataFrame using progress_apply()
Result_apply = df.progress_apply(lambda x: x / 2)
 
# Doubling each element of the first column using progress_map()
result_map = df[0].progress_map(lambda x: x * 2)

Tqdm: Problemas comunes y soluciones

Analicemos algunos problemas y errores comunes de Tqdm y aprendamos a solucionarlos.

La barra de progreso no se actualiza

Uno de los problemas más frecuentes al utilizar tqdm es que la barra de progreso no se actualiza. Esto ocurre a menudo debido a problemas de almacenamiento en búfer, especialmente en entornos como Cuadernos Jupyter. Cuando la salida se almacena en la memoria intermedia, es posible que la barra de progreso no se muestre o actualice inmediatamente, dando lugar a la percepción de un proceso congelado o que no responde.

Utilizando el módulo tqdm.notebook se pueden solucionar los problemas de almacenamiento en búfer y garantizar que la barra de progreso se actualice correctamente en los Cuadernos Jupyter. Este módulo proporciona una barra de progreso basada en GUI que está diseñada específicamente para entornos Jupyter.

Además, ofrece indicaciones de color fáciles de usar (azul: normal, verde: completado, rojo: error/interrupción).

Si interrumpimos el código de nuestro ejemplo de barra de progreso anidada, queda así:

Captura de pantalla que muestra la ejecución interrumpida de tres barras de progreso anidadas en un Cuaderno Jupyter. Todas las barras completadas son de color verde, mientras que todas las interrumpidas son de color rojo.

Barras de progreso anidadas en Python utilizando tqdm.notebook, ilustrando el esquema de colores de las barras completadas frente a las interrumpidas.

Otra forma eficaz de solucionar el problema de las barras de progreso que no se actualizan es vaciar explícitamente el flujo de salida. Cuando se escriben datos en el flujo de salida estándar (por ejemplo, utilizando print()), los datos suelen almacenarse en un búfer antes de ser enviados al dispositivo de salida real. La descarga del flujo de salida obliga al intérprete de Python a enviar inmediatamente cualquier dato almacenado en el búfer al dispositivo de salida, garantizando que los datos se muestren o escriban sin demora. 

Para vaciar la salida, utiliza el método flush() del flujo de salida estándar. Para obtener una salida más sensible, considera la posibilidad de vaciar el flujo de salida con más frecuencia, quizás cada pocas iteraciones o después de cierto tiempo. Ten en cuenta que hay una compensación, ya que vaciar el flujo de salida puede introducir una sobrecarga adicional. He aquí un ejemplo de cómo incorporar el método a un proceso sencillo de tqdm:

import sys
import time
from tqdm import tqdm
 
for i in tqdm(range(100)):
	time.sleep(0.1)
	sys.stdout.flush()  # Flush the output stream after each iteration

Problemas de compatibilidad

Aunque tqdm es generalmente compatible con la mayoría de los entornos y bibliotecas de Python, puede haber problemas ocasionales de compatibilidad o comportamientos inesperados. Algunas situaciones habituales que hay que tener en cuenta son

  • Flujos de salida personalizados: Al utilizar flujos de salida personalizados o redirigir la salida a archivos, es posible que tqdm no funcione como se espera. Debemos asegurarnos de que el flujo de salida que utilizamos admite las operaciones necesarias para mostrar la barra de progreso.
  • Bibliotecas de terceros: En algunos casos, tqdm puede interactuar de forma inesperada con bibliotecas de terceros, especialmente con las que gestionan ellas mismas la salida o el seguimiento del progreso. Podemos probar a desactivar o modificar las funciones pertinentes de la biblioteca de terceros para ver si se resuelve el problema.
  • Compatibilidad de la versión: Siempre es una buena práctica utilizar versiones compatibles de tqdm y otras bibliotecas. Consulta la documentación de la biblioteca para conocer cualquier problema de compatibilidad conocido con versiones específicas de Python u otras dependencias.

Cuando nos encontremos con problemas de compatibilidad, podemos considerar las siguientes soluciones:

  • Baja o sube: Podemos probar una versión diferente de tqdm.
  • Modifica el código: Si es necesario, podemos hacer ajustes en nuestro código para solucionar cualquier conflicto de compatibilidad.
  • Busca ayuda en la comunidad: Si todo eso no ayuda, podemos acudir a la comunidad tqdm o a los foros en línea en busca de ayuda y posibles soluciones.

Teniendo en cuenta estos posibles problemas de compatibilidad y sus soluciones, podemos solucionar eficazmente cualquier problema que surja al utilizar tqdm en nuestros proyectos de proyectos Python.

Conclusión

En conclusión, Tqdm es una biblioteca de Python que nos proporciona barras de progreso y otras estadísticas útiles, facilitando la supervisión y gestión de la ejecución del código.

Si estás iterando sobre grandes conjuntos de datos, entrenando modelos de aprendizaje automáticoo cualquier otra operación que requiera mucho tiempo, tqdm te ofrece una forma sencilla pero eficaz de controlar el progreso y mantenerte informado sobre el estado de tu código.

Para profundizar más, no dudes en consultar los otros tutoriales de Python del DataCampy la documentación de Tqdmo su código fuente y Readme en GitHub.

Preguntas frecuentes

¿Cómo puedo crear una barra de progreso sencilla con tqdm?

Instala e importa la biblioteca tqdm, y luego envuelve tu iterable con la función tqdm().

¿Puedo utilizar tqdm con pandas DataFrames u otras bibliotecas?

Sí, puedes utilizar tqdm con pandas DataFrames y otras bibliotecas. El módulo tqdm.pandas proporciona funciones específicas para integrar tqdm con pandas.

¿Puedo personalizar el aspecto de la barra de progreso de Tqdm?

Sí, puedes personalizar el formato de la barra, el color, el número total de iteraciones y mucho más utilizando los parámetros de Tqdm.

La barra de progreso de Tqdm no se actualiza correctamente, ¿qué debo hacer?

Comprueba si hay problemas de almacenamiento en búfer, especialmente en los cuadernos Jupyter. Prueba a utilizar tqdm.notebook o a vaciar explícitamente la salida. Asegúrate también de que se utilizan correctamente los parámetros de total.


Photo of Tom Farnschläder
Author
Tom Farnschläder
LinkedIn

Tras construir una base sólida en economía, derecho y contabilidad en mis estudios duales en la administración financiera regional, entré en contacto por primera vez con la estadística en mis estudios de ciencias sociales y mi trabajo como tutora. Realizando análisis empíricos cuantitativos, descubrí una pasión que me llevó a continuar mi viaje adentrándome en el hermoso campo de la ciencia de datos y a aprender herramientas analíticas como R, SQL y Python. Actualmente, estoy mejorando mis habilidades prácticas en Deutsche Telekom, donde puedo recibir mucha experiencia práctica en la codificación de rutas de datos para importar, procesar y analizar datos utilizando Python.

Temas

Los mejores cursos de Python

Course

Introduction to Python for Developers

3 hr
20.9K
Master the fundamentals of programming in Python. No prior knowledge required!
See DetailsRight Arrow
Start Course
Ver másRight Arrow
Relacionado

tutorial

Introducción al trazado con Matplotlib en Python

Este tutorial muestra cómo utilizar Matplotlib, una potente biblioteca de visualización de datos en Python, para crear gráficos de líneas, barras y dispersión con datos bursátiles.

Kevin Babitz

25 min

tutorial

Pandas Profiling (ydata-profiling) en Python: Guía para principiantes

Aprenda a utilizar la biblioteca ydata-profiling en Python para generar informes detallados de conjuntos de datos con muchas características.
Satyam Tripathi's photo

Satyam Tripathi

9 min

tutorial

Tutorial de multiprocesamiento en Python

Descubra los fundamentos del multiprocesamiento en Python y las ventajas que puede aportar a sus flujos de trabajo.
Kurtis Pykes 's photo

Kurtis Pykes

6 min

tutorial

Tutorial de visualización de datos con Python y Tableau

Aprende a utilizar Python para ampliar las funciones de visualización de datos de Tableau.
Abid Ali Awan's photo

Abid Ali Awan

15 min

tutorial

Tutorial de Docstrings en Python

Aprende sobre las Docstrings de Python. Encuentra diferentes ejemplos y tipos de formato de docstrings para Sphinx, Numpy y Pydoc.
Aditya Sharma's photo

Aditya Sharma

15 min

tutorial

Tutorial y Ejemplos de Funciones y Métodos de Listas en Python

Conozca las funciones y métodos de lista de Python. Siga ahora ejemplos de código de list() y otras funciones y métodos de Python.
Abid Ali Awan's photo

Abid Ali Awan

7 min

See MoreSee More