Skip to main content

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 que fastcore.groupby(), pero devuelve otro FastList (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 que fast_sum). Con argumento, asume que el FastList viene de un .groupby() y devuelve un dict {clave: suma_del_campo}.
  • .count() — asume que el FastList viene 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_bygroupbysum/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

fastcorex-0.1.1.tar.gz (9.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastcorex-0.1.1-cp314-cp314-android_24_arm64_v8a.whl (22.4 kB view details)

Uploaded Android API level 24+ ARM64 v8aCPython 3.14

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

Hashes for fastcorex-0.1.1.tar.gz
Algorithm Hash digest
SHA256 5780139ad0d6232c580ebbd26505899aa7e2b4bfa214b6f249915a4be42d2354
MD5 ea80d107b362d8afe811640bec2f1535
BLAKE2b-256 3e7e8a41883873a6ea0ae6e9d2e0e2537893ebe101abef7d8cb1cb1b0feb7ea7

See more details on using hashes here.

File details

Details for the file fastcorex-0.1.1-cp314-cp314-android_24_arm64_v8a.whl.

File metadata

File hashes

Hashes for fastcorex-0.1.1-cp314-cp314-android_24_arm64_v8a.whl
Algorithm Hash digest
SHA256 b67f9ead77c4b8ea43610ae1af2b52e8ce725be892f3673c76e6191bf9f05c6e
MD5 cd2c9de5f16b2579270e5b498fcd660e
BLAKE2b-256 b5acf861e46d691f43d581485f305ddf1e8542ae9c518329c2525e1ea3890c20

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page