FastCore
Project description
fastcore
Extensión en C para acelerar loops y estructuras de datos comunes en Python. No es un reemplazo completo de tu flujo de trabajo — es una capa delgada que elimina las partes tediosas y repetitivas (agrupar, deduplicar, aplanar, contar frecuencias, particionar, acceso anidado seguro) que normalmente reescribes a mano en cada proyecto.
Instalación
pip install fastcore
Uso rápido
import fastcore
fastcore.fast_sum([1, 2, 3]) # 6.0 fastcore.count_freq(["a", "b", "a"]) # {'a': 2, 'b': 1} fastcore.unique([3, 1, 2, 1, 3]) # [3, 1, 2] fastcore.filter_gt([1, 5, 10, 3], 4.0) # [5.0, 10.0] fastcore.groupby(lista_de_dicts, "categoria") # dict agrupado fastcore.flatten([1, [2, [3, 4]], 5]) # [1, 2, 3, 4, 5] fastcore.unique_by(lista_de_dicts, "id") # FastList dedup por campo (encadenable) fastcore.chunk([1, 2, 3, 4, 5], 2) # [[1, 2], [3, 4], [5]] fastcore.safe_get(d, "a.b.c", default=None) # acceso anidado sin try/except fastcore.clamp(15.0, 0.0, 10.0) # 10.0
Documentación de funciones
fast_sum(lista) — Suma todos los elementos numéricos de una lista. fastcore.fast_sum([1, 2, 3, 4.5]) # 10.5
count_freq(lista) — Cuenta cuántas veces aparece cada elemento. Reemplaza un loop de 4 líneas con dict.get() por una sola llamada. fastcore.count_freq(["a", "b", "a", "c", "b", "a"]) # {'a': 3, 'b': 2, 'c': 1}
unique(lista) — Elimina duplicados manteniendo el orden original. Reemplaza el patrón de set() + loop + append. fastcore.unique([3, 1, 2, 1, 3, 4]) # [3, 1, 2, 4]
filter_gt(lista, umbral) — Devuelve solo los elementos mayores al umbral dado. fastcore.filter_gt([1, 5, 10, 3, 8], 4.0) # [5.0, 10.0, 8.0]
groupby(lista_de_dicts, clave) — Agrupa una lista de diccionarios según el valor de una clave. Devuelve un dict normal. Reemplaza el patrón de dict + setdefault manual. fastcore.groupby(ventas, "categoria") # {'ropa': [...], 'comida': [...]}
flatten(lista_anidada) — Aplana listas anidadas de cualquier profundidad. Reemplaza una función recursiva escrita a mano. fastcore.flatten([1, [2, 3, [4, [5, 6]], 7], 8]) # [1, 2, 3, 4, 5, 6, 7, 8]
unique_by(lista_de_dicts, clave) — Deduplica diccionarios según el valor de un campo específico, no el objeto completo. A diferencia de las demás, devuelve un FastList en vez de una lista normal (ver sección de encadenamiento más abajo).
fastcore.unique_by(ventas, "id") # FastList sin ids repetidos
chunk(lista, tamaño) — Parte una lista en sublistas de tamaño fijo; el último chunk puede quedar más corto. Reemplaza el slicing manual con range(0, len(lista), tamaño). fastcore.chunk([1, 2, 3, 4, 5, 6, 7], 3) # [[1, 2, 3], [4, 5, 6], [7]]
safe_get(dict, "a.b.c", default=None) — Acceso anidado seguro a diccionarios usando un path con puntos. Reemplaza el try/except (KeyError, TypeError) que normalmente envuelve un acceso encadenado. fastcore.safe_get({"a": {"b": {"c": 42}}}, "a.b.c") # 42 fastcore.safe_get({"a": {"b": {}}}, "a.b.c", default="N/A") # "N/A"
clamp(valor, minimo, maximo) — Acota un número al rango [minimo, maximo]. Reemplaza max(minimo, min(valor, maximo)) o un if/elif/else. fastcore.clamp(15.0, 0.0, 10.0) # 10.0 fastcore.clamp(-5.0, 0.0, 10.0) # 0.0
FastList: encadenamiento de métodos
unique_by() devuelve un FastList, un subtipo de list que además de comportarse como una lista normal (indexable, iterable, con len(), etc.) expone tres métodos propios para seguir encadenando sin volver a pasar por funciones sueltas del módulo:
.groupby(clave)— igual quefastcore.groupby(), pero devuelve otroFastList(de pares[clave, sublista]) en vez de un dict, precisamente para poder seguir encadenando..sum(campo=None)— sin argumento, suma los elementos como números (igual quefast_sum). Con argumento, asume que elFastListviene de un.groupby()y devuelve un dict{clave: suma_del_campo}..count()— asume que elFastListviene de un.groupby()y devuelve un dict{clave: cantidad}.
ventas_unicas = fastcore.unique_by(ventas, "id") totales = ventas_unicas.groupby("categoria").sum("monto")
{'ropa': 240.0, 'comida': 30.0, 'tech': 500.0}
conteos = ventas_unicas.groupby("categoria").count()
{'ropa': 2, 'comida': 1, 'tech': 1}
También podés construir un FastList directamente si querés esta API encadenada desde el principio:
plano = fastcore.FastList([1.0, 2.0, 3.0]) plano.sum() # 6.0
Nota: .sum(campo) y .count() esperan específicamente el formato que produce .groupby() (una lista de pares [clave, sublista]); si les pasás otra cosa, tiran TypeError con un mensaje explicando qué esperaban.
Ejemplo real combinando varias funciones
Sin fastcore (19 líneas): un loop para deduplicar por id con set() + seen, otro loop para agrupar por categoría con dict + setdefault, y un tercer loop anidado para sumar montos por grupo.
Con fastcore, dos formas equivalentes:
Con funciones sueltas (4 líneas):
ventas_unicas = fastcore.unique_by(ventas, "id") grupos = fastcore.groupby(ventas_unicas, "categoria") totales = {cat: fastcore.fast_sum([i["monto"] for i in items]) for cat, items in grupos.items()}
Con encadenamiento de FastList (2 líneas):
ventas_unicas = fastcore.unique_by(ventas, "id") totales = ventas_unicas.groupby("categoria").sum("monto")
Ambas versiones dan el mismo resultado: {'ropa': 240.0, 'comida': 30.0, 'tech': 500.0}
Resultados de benchmark
Medido con listas de 200,000 y 2,000,000 de elementos, mejor tiempo de 5 corridas. Datos generados aleatoriamente por función (números, strings de un alfabeto de 50 valores, dicts con ~50% de ids duplicados para forzar deduplicación real en unique_by).
Con 200,000 elementos: fast_sum 6.0x más rápido, count_freq 1.5x, unique 1.3x, filter_gt 2.0x, groupby 2.0x, flatten 14.4x, unique_by 1.4x, chunk 1.3x, clamp 2.5x, pipeline encadenado completo (unique_by → groupby → sum) 1.7x. safe_get: 0.77x — más lento que Python puro.
Con 2,000,000 elementos: fast_sum 4.3x, count_freq 1.6x, unique 1.3x, filter_gt 1.7x, groupby 1.7x, flatten 9.0x, unique_by 1.5x, chunk 1.1x, clamp 2.3x, pipeline encadenado 1.6x. safe_get: 0.75x — más lento que Python puro.
flatten sigue teniendo la mayor ganancia porque en Python puro depende de recursión con overhead de llamadas a función, que en C es casi gratis. groupby y el pipeline encadenado ganan bien porque evitan el overhead del bytecode en el loop principal. Las funciones que ya dependen de dict/set de Python (count_freq, unique, unique_by, fast_sum) ganan menos, porque esas estructuras ya están optimizadas en C por debajo del intérprete — el beneficio ahí es sobre todo la reducción de líneas de código, no la velocidad. chunk gana relativamente poco porque el slicing de listas en Python ya es una operación en C bien optimizada.
safe_get es la excepción real: es consistentemente ~25% más lento que el equivalente en Python. La implementación actual hace strdup() + strtok() sobre el path en cada llamada (con su malloc/free correspondiente) y usa PyDict_GetItemString, que internamente construye un objeto string de Python por cada segmento del path — trabajo que la versión pura de Python no necesita porque ya opera sobre objetos string existentes. Si te importa la velocidad de esta función en particular, por ahora conviene usar el patrón try/except nativo en su lugar; queda pendiente optimizar la implementación en C (por ejemplo pre-parseando el path una sola vez o usando PyDict_GetItemWithError sobre substrings ya convertidos).
Licencia
MIT License. Ver el archivo LICENSE para el texto completo.
Estado del proyecto
Versión 0.1.1. Cubre patrones comunes de listas y diccionarios (agrupar, deduplicar, aplanar, contar, filtrar, sumar, particionar, acceso anidado, acotar rangos) más un tipo FastList para encadenar unique_by → groupby → sum/count sin pasar por dicts intermedios. No pretende reemplazar NumPy para cómputo numérico ni Pandas para análisis de datos tabulares — está enfocado en el trabajo genérico con listas y diccionarios que esas librerías no cubren directamente.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastcorex-0.1.1.tar.gz.
File metadata
- Download URL: fastcorex-0.1.1.tar.gz
- Upload date:
- Size: 9.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: python-requests/2.34.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5780139ad0d6232c580ebbd26505899aa7e2b4bfa214b6f249915a4be42d2354
|
|
| MD5 |
ea80d107b362d8afe811640bec2f1535
|
|
| BLAKE2b-256 |
3e7e8a41883873a6ea0ae6e9d2e0e2537893ebe101abef7d8cb1cb1b0feb7ea7
|
File details
Details for the file fastcorex-0.1.1-cp314-cp314-android_24_arm64_v8a.whl.
File metadata
- Download URL: fastcorex-0.1.1-cp314-cp314-android_24_arm64_v8a.whl
- Upload date:
- Size: 22.4 kB
- Tags: Android API level 24+ ARM64 v8a, CPython 3.14
- Uploaded using Trusted Publishing? No
- Uploaded via: python-requests/2.34.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b67f9ead77c4b8ea43610ae1af2b52e8ce725be892f3673c76e6191bf9f05c6e
|
|
| MD5 |
cd2c9de5f16b2579270e5b498fcd660e
|
|
| BLAKE2b-256 |
b5acf861e46d691f43d581485f305ddf1e8542ae9c518329c2525e1ea3890c20
|