Skip to content

Python F-Strings: La Guía Completa para el Formato de Cadenas

Updated on

El formateo de cadenas es una de las operaciones más comunes en Python, pero ha sido una fuente de frustración durante años. El operador % utiliza códigos de formato crípticos heredados de C. El método .format() dispersa los valores lejos de donde aparecen en la plantilla. La concatenación de cadenas con + te obliga a convertir tipos manualmente y produce código desordenado y difícil de leer. Cada enfoque parece añadir fricción a lo que debería ser una tarea simple: poner un valor dentro de una cadena.

El problema empeora en proyectos reales. Necesitas formatear moneda con dos decimales, alinear columnas en un reporte, rellenar números con ceros iniciales, mostrar porcentajes y formatear marcas de tiempo, todo mientras mantienes el código legible. Con los métodos de formateo más antiguos, terminas manteniendo dos estructuras paralelas: la cadena plantilla y la lista de argumentos. Un solo error al reordenar rompe todo silenciosamente, produciendo salida incorrecta en lugar de un error.

Python 3.6 introdujo los f-strings (literales de cadena formateadas), y cambiaron el formateo de cadenas permanentemente. Al prefijar una cadena con f e incrustar expresiones directamente dentro de {llaves}, los f-strings mantienen los valores junto a donde aparecen. Son más rápidos que cualquier otro método de formateo. Soportan el rango completo de especificaciones de formato. Y en Python 3.8, ganaron una característica de depuración incorporada con el especificador =. Esta guía cubre cada capacidad de los f-strings con ejemplos prácticos y ejecutables.

📚

¿Qué Son los F-Strings?

Los f-strings, formalmente llamados "literales de cadena formateadas", fueron introducidos en PEP 498 (opens in a new tab) y lanzados con Python 3.6. El concepto es simple: prefija cualquier cadena con f (o F), y Python evalúa cualquier expresión dentro de llaves {} en tiempo de ejecución, convirtiendo el resultado a cadena e insertándolo en la salida.

name = "Alice"
age = 30
 
greeting = f"My name is {name} and I am {age} years old."
print(greeting)
# Output: My name is Alice and I am 30 years old.

El prefijo f funciona con comillas simples, comillas dobles y comillas triples:

single = f'Hello, {name}'
double = f"Hello, {name}"
triple_double = f"""Hello, {name}"""
triple_single = f'''Hello, {name}'''

En el fondo, Python compila los f-strings en una serie de concatenaciones de cadenas y operaciones format() en tiempo de análisis. Esta es la razón por la que los f-strings son más rápidos que llamar .format() tú mismo -- el intérprete optimiza la operación directamente.

Sintaxis Básica de F-Strings

La sintaxis central es sencilla: escribe f"texto {expresión} más texto". Python evalúa la expresión, llama str() en el resultado, y lo inserta en la cadena.

# Variables
city = "Tokyo"
population = 13960000
 
print(f"{city} has a population of {population}.")
# Output: Tokyo has a population of 13960000.
 
# You can use either f or F
print(F"Welcome to {city}!")
# Output: Welcome to Tokyo!

Puedes colocar cualquier número de expresiones dentro de un solo f-string:

first = "Grace"
last = "Hopper"
title = "Rear Admiral"
year = 1906
 
bio = f"{title} {first} {last}, born {year}, lived to {1992 - year} years."
print(bio)
# Output: Rear Admiral Grace Hopper, born 1906, lived to 86 years.

Expresiones Dentro de F-Strings

Los f-strings no solo insertan variables. Evalúan cualquier expresión de Python válida entre las llaves. Esto incluye aritmética, llamadas a métodos, llamadas a funciones, expresiones ternarias, indexación de listas, acceso a diccionarios, y más.

Aritmética y Matemáticas

x = 15
y = 4
 
print(f"{x} + {y} = {x + y}")
print(f"{x} / {y} = {x / y:.2f}")
print(f"{x} ** {y} = {x ** y}")
print(f"{x} % {y} = {x % y}")
# Output:
# 15 + 4 = 19
# 15 / 4 = 3.75
# 15 ** 4 = 50625
# 15 % 4 = 3

Llamadas a Métodos

text = "  hello, python world  "
 
print(f"Stripped: '{text.strip()}'")
print(f"Title case: '{text.strip().title()}'")
print(f"Upper: '{text.strip().upper()}'")
print(f"Replace: '{text.strip().replace('python', 'f-string')}'")
# Output:
# Stripped: 'hello, python world'
# Title case: 'Hello, Python World'
# Upper: 'HELLO, PYTHON WORLD'
# Replace: 'hello, f-string world'

Llamadas a Funciones

def calculate_bmi(weight_kg, height_m):
    return weight_kg / (height_m ** 2)
 
weight = 70
height = 1.75
 
print(f"BMI: {calculate_bmi(weight, height):.1f}")
# Output: BMI: 22.9
 
# Built-in functions
items = [3, 1, 4, 1, 5, 9, 2, 6]
print(f"Items: {items}")
print(f"Count: {len(items)}, Sum: {sum(items)}, Min: {min(items)}, Max: {max(items)}")
# Output:
# Items: [3, 1, 4, 1, 5, 9, 2, 6]
# Count: 8, Sum: 31, Min: 1, Max: 9

Expresiones Ternarias (Condicionales)

score = 85
status = f"Result: {'PASS' if score >= 60 else 'FAIL'}"
print(status)
# Output: Result: PASS
 
temperature = -5
print(f"Water is {'frozen' if temperature <= 0 else 'liquid' if temperature < 100 else 'steam'}.")
# Output: Water is frozen.

Acceso a Diccionarios y Listas

user = {"name": "Bob", "role": "engineer", "level": 3}
scores = [88, 92, 76, 95, 81]
 
print(f"{user['name']} is a level {user['level']} {user['role']}.")
# Output: Bob is a level 3 engineer.
 
print(f"First score: {scores[0]}, Last score: {scores[-1]}")
# Output: First score: 88, Last score: 81

Especificaciones de Formato: Números, Alineación y Relleno

El verdadero poder de los f-strings se muestra en las especificaciones de formato. Después de la expresión, añade dos puntos : seguidos de una especificación de formato. La sintaxis general es:

{expresión:[[relleno]alineación][signo][#][0][ancho][opción_agrupamiento][.precisión][tipo]}

Esto parece denso, pero cada pieza es opcional. Desglosemoslo con ejemplos.

Decimales y Precisión de Punto Flotante

El especificador .Nf controla cuántos lugares decimales muestra un float:

pi = 3.141592653589793
 
print(f"Default:    {pi}")
print(f"2 decimals: {pi:.2f}")
print(f"4 decimals: {pi:.4f}")
print(f"0 decimals: {pi:.0f}")
print(f"8 decimals: {pi:.8f}")
# Output:
# Default:    3.141592653589793
# 2 decimals: 3.14
# 4 decimals: 3.1416
# 0 decimals: 3
# 8 decimals: 3.14159265

Separadores de Miles

Los números grandes se vuelven legibles instantáneamente con agrupamiento por comas o guiones bajos:

revenue = 1234567890
small_amount = 1234.5
 
print(f"Revenue: {revenue:,}")
print(f"Revenue: {revenue:_}")
print(f"Amount: ${small_amount:,.2f}")
# Output:
# Revenue: 1,234,567,890
# Revenue: 1_234_567_890
# Amount: $1,234.50

Formateo de Porcentajes

El tipo % multiplica el valor por 100 y añade un signo de porcentaje:

completion = 0.876
error_rate = 0.034
growth = 1.25
 
print(f"Completion: {completion:.1%}")
print(f"Error rate: {error_rate:.2%}")
print(f"Growth: {growth:.0%}")
# Output:
# Completion: 87.6%
# Error rate: 3.40%
# Growth: 125%

Notación Científica

avogadro = 6.022e23
planck = 6.626e-34
 
print(f"Avogadro: {avogadro:.3e}")
print(f"Planck: {planck:.4E}")
# Output:
# Avogadro: 6.022e+23
# Planck: 6.6260E-34

Bases Enteras: Binario, Octal, Hexadecimal

value = 255
 
print(f"Decimal:     {value:d}")
print(f"Binary:      {value:b}")
print(f"Octal:       {value:o}")
print(f"Hex (lower): {value:x}")
print(f"Hex (upper): {value:X}")
print(f"With prefix: {value:#b}  {value:#o}  {value:#x}")
# Output:
# Decimal:     255
# Binary:      11111111
# Octal:       377
# Hex (lower): ff
# Hex (upper): FF
# With prefix: 0b11111111  0o377  0xff

Alineación y Relleno

Los especificadores de alineación controlan cómo se sitúan los valores dentro de un ancho dado. Usa < para izquierda, > para derecha, y ^ para centro:

label = "Python"
 
print(f"|{label:<20}|")   # Left-align in 20 chars
print(f"|{label:>20}|")   # Right-align
print(f"|{label:^20}|")   # Center
print(f"|{label:*^20}|")  # Center with * fill
print(f"|{label:->20}|")  # Right with - fill
# Output:
# |Python              |
# |              Python|
# |       Python       |
# |*******Python*******|
# |--------------Python|

El relleno con ceros para números es común en el formateo de reportes:

for i in [1, 42, 100, 7, 999]:
    print(f"ID: {i:05d}")
# Output:
# ID: 00001
# ID: 00042
# ID: 00100
# ID: 00007
# ID: 00999

Construcción de Tablas Alineadas

Combinar la alineación con especificaciones de formato produce tablas limpias:

products = [
    ("Laptop Pro", 1299.99, 45),
    ("Wireless Mouse", 29.50, 230),
    ("USB-C Hub", 54.95, 120),
    ("Monitor 27in", 449.00, 67),
]
 
print(f"{'Product':<18} {'Price':>10} {'Stock':>7}")
print("-" * 37)
for name, price, stock in products:
    print(f"{name:<18} ${price:>9.2f} {stock:>7,}")
print("-" * 37)
 
total_value = sum(p * s for _, p, s in products)
print(f"{'Total Value':<18} ${total_value:>9,.2f}")
 
# Output:
# Product               Price   Stock
# -------------------------------------
# Laptop Pro         $ 1,299.99      45
# Wireless Mouse     $    29.50     230
# USB-C Hub          $    54.95     120
# Monitor 27in       $   449.00      67
# -------------------------------------
# Total Value        $91,498.05

Formateo de Fecha y Hora con F-Strings

Los f-strings aceptan códigos de formato strftime directamente, lo que significa que puedes formatear objetos datetime sin llamar a .strftime():

from datetime import datetime, date, timedelta
 
now = datetime.now()
 
print(f"ISO format:  {now:%Y-%m-%d %H:%M:%S}")
print(f"US format:   {now:%m/%d/%Y}")
print(f"Long format: {now:%B %d, %Y at %I:%M %p}")
print(f"Day of week: {now:%A}")
print(f"Short month: {now:%b %d}")
# Output (varies by current time):
# ISO format:  2026-02-13 14:30:00
# US format:   02/13/2026
# Long format: February 13, 2026 at 02:30 PM
# Day of week: Friday
# Short month: Feb 13

Esto también funciona con objetos date:

from datetime import date
 
birthday = date(1995, 8, 15)
today = date.today()
age_days = (today - birthday).days
 
print(f"Birthday: {birthday:%B %d, %Y}")
print(f"Days alive: {age_days:,}")
print(f"Years (approx): {age_days / 365.25:.1f}")
# Output:
# Birthday: August 15, 1995
# Days alive: 11,139
# Years (approx): 30.5

F-Strings Multilínea

Los f-strings con comillas triples te permiten construir bloques de texto formateados. Cada línea en un f-string con comillas triples puede contener expresiones {}:

project = "Data Pipeline"
owner = "Engineering Team"
status = "In Progress"
completion = 0.73
budget = 250000
spent = 182500
 
report = f"""
========================================
  Project Status Report
========================================
  Project:    {project}
  Owner:      {owner}
  Status:     {status}
  Completion: {completion:.0%}
  Budget:     ${budget:>12,}
  Spent:      ${spent:>12,}
  Remaining:  ${budget - spent:>12,}
========================================
"""
 
print(report)

También puedes construir f-strings multilínea concatenando múltiples f-strings con concatenación implícita de cadenas (colocándolos uno al lado del otro sin operador):

name = "Alice"
role = "Data Scientist"
years = 5
 
bio = (
    f"Name: {name}\n"
    f"Role: {role}\n"
    f"Experience: {years} years\n"
    f"Seniority: {'Senior' if years >= 5 else 'Mid-level'}"
)
 
print(bio)
# Output:
# Name: Alice
# Role: Data Scientist
# Experience: 5 years
# Seniority: Senior

Este segundo enfoque evita la nueva línea inicial y los problemas de indentación que a veces vienen con cadenas de comillas triples.

El Especificador = para Depuración (Python 3.8+)

Python 3.8 añadió el especificador = a los f-strings, y es una de las características de depuración más útiles del lenguaje. Cuando escribes f"{expresión=}", Python imprime tanto el texto de la expresión como su valor.

x = 42
y = 17
 
print(f"{x=}")
print(f"{y=}")
print(f"{x + y=}")
print(f"{x * y=}")
# Output:
# x=42
# y=17
# x + y=59
# x * y=714

Puedes combinar = con especificadores de formato:

price = 49.99
tax_rate = 0.0825
total = price * (1 + tax_rate)
 
print(f"{price=:.2f}")
print(f"{tax_rate=:.1%}")
print(f"{total=:.2f}")
# Output:
# price=49.99
# tax_rate=8.2%
# total=54.12

El especificador = preserva los espacios en blanco alrededor de él. Añadir espacios antes de = formatea la salida:

name = "Alice"
score = 95
 
print(f"{name = }")
print(f"{score = }")
# Output:
# name = 'Alice'
# score = 95

Nota que para cadenas, = usa repr() por defecto (mostrando las comillas). Para números, usa str().

Depuración de Expresiones Complejas

El especificador = funciona con cualquier expresión, haciéndolo una forma rápida de inspeccionar valores intermedios:

data = [23, 45, 12, 67, 34, 89, 56]
 
print(f"{len(data)=}")
print(f"{sum(data)=}")
print(f"{sum(data)/len(data)=:.2f}")
print(f"{sorted(data)=}")
print(f"{max(data) - min(data)=}")
# Output:
# len(data)=7
# sum(data)=326
# sum(data)/len(data)=46.57
# sorted(data)=[12, 23, 34, 45, 56, 67, 89]
# max(data) - min(data)=77

Si trabajas en notebooks de Jupyter y te encuentras constantemente añadiendo llamadas print(f"{variable=}") mientras depuras, considera RunCell (opens in a new tab), un agente de IA que se ejecuta directamente dentro de Jupyter. RunCell entiende las variables en la memoria de tu notebook y puede inspeccionar, explicar y sugerir correcciones sin que tengas que escribir declaraciones de depuración manualmente. Es especialmente útil cuando recorres transformaciones de datos donde necesitas verificar valores intermedios a través de múltiples celdas.

F-Strings Anidados

Puedes anidar f-strings dentro de f-strings. El caso de uso más común son las especificaciones de formato dinámico, donde el ancho o la precisión provienen de una variable:

# Dynamic precision
value = 3.14159265
for precision in range(1, 6):
    print(f"  {precision} decimals: {value:.{precision}f}")
# Output:
#   1 decimals: 3.1
#   2 decimals: 3.14
#   3 decimals: 3.142
#   4 decimals: 3.1416
#   5 decimals: 3.14159
# Dynamic width
header = "Report"
for width in [20, 30, 40]:
    print(f"|{header:^{width}}|")
# Output:
# |       Report       |
# |            Report            |
# |                 Report                 |
# Nested f-string for formatting a list
values = [1.234, 56.789, 0.001, 999.999]
decimals = 2
formatted = f"Results: {', '.join(f'{v:.{decimals}f}' for v in values)}"
print(formatted)
# Output: Results: 1.23, 56.79, 0.00, 1000.00

Usa el anidamiento con moderación. Si un f-string requiere más de un nivel de anidamiento, extrae la lógica interna en una variable o función para mejorar la legibilidad.

F-Strings vs Otros Métodos de Formateo de Cadenas

Python tiene cuatro enfoques principales para el formateo de cadenas. Aquí hay una comparación directa:

Característicaf-string f"...{x}...".format() "...{}...".format(x)Operador % "...%s..." % xTemplate Template("...$x...")
Versión de Python3.6+2.6+TodasTodas
LegibilidadExcelente -- valores en líneaBuena -- marcadores numerados/nombradosRegular -- códigos posicionalesBuena -- marcadores nombrados
RendimientoEl más rápido~1.5-2x más lento~1.3-1.8x más lentoEl más lento
Expresiones ArbitrariasLimitadoNoNo
Especificador de Depuración (=)Sí (3.8+)NoNoNo
Plantillas ReutilizablesNo
Seguro para Entrada de UsuarioNoNoNoSí (safe_substitute)
Formateo de TiposCompletoCompletoParcialNinguno
name = "Charlie"
balance = 1234.56
 
# f-string (recommended)
print(f"{name} has ${balance:,.2f}")
 
# .format()
print("{} has ${:,.2f}".format(name, balance))
 
# % formatting
print("%s has $%,.2f" % (name, balance))  # Note: %  does not support comma grouping
 
# Template (from string module)
from string import Template
t = Template("$name has $balance")
print(t.substitute(name=name, balance=f"${balance:,.2f}"))

Cuándo usar cada uno:

  • F-strings: Opción predeterminada para código nuevo. Úsalos siempre que ejecutes Python 3.6+.
  • .format(): Úsalo cuando necesites plantillas reutilizables almacenadas en variables o archivos de configuración.
  • % formateo: Solo código heredado. No hay razón para usarlo en proyectos nuevos.
  • Template: Úsalo cuando la cadena de formato proviene de entrada de usuario no confiable (no puede ejecutar expresiones arbitrarias).

Comparación de Rendimiento

Los f-strings son más rápidos porque Python los compila en bytecode optimizado en tiempo de análisis, evitando la sobrecarga de llamadas a métodos y análisis de argumentos que requieren .format() y %.

import timeit
 
name = "Alice"
age = 30
score = 95.5
 
# Benchmark each method with 1 million iterations
fstring_time = timeit.timeit(
    'f"{name} scored {score:.1f} at age {age}"',
    globals={"name": name, "age": age, "score": score},
    number=1_000_000
)
 
format_time = timeit.timeit(
    '"{} scored {:.1f} at age {}".format(name, score, age)',
    globals={"name": name, "age": age, "score": score},
    number=1_000_000
)
 
percent_time = timeit.timeit(
    '"%s scored %.1f at age %d" % (name, score, age)',
    globals={"name": name, "age": age, "score": score},
    number=1_000_000
)
 
concat_time = timeit.timeit(
    'name + " scored " + str(score) + " at age " + str(age)',
    globals={"name": name, "age": age, "score": score},
    number=1_000_000
)
 
print(f"f-string:      {fstring_time:.4f}s (baseline)")
print(f"str.format():  {format_time:.4f}s ({format_time/fstring_time:.2f}x slower)")
print(f"% formatting:  {percent_time:.4f}s ({percent_time/fstring_time:.2f}x slower)")
print(f"concatenation: {concat_time:.4f}s ({concat_time/fstring_time:.2f}x slower)")
 
# Typical results:
# f-string:      0.0850s (baseline)
# str.format():  0.1450s (1.71x slower)
# % formatting:  0.1100s (1.29x slower)
# concatenation: 0.1200s (1.41x slower)

La brecha de rendimiento se amplía a medida que las expresiones se vuelven más complejas. En bucles cerrados procesando miles de registros, los f-strings hacen una diferencia medible.

Errores Comunes y Advertencias

Escapando Llaves

Para incluir una { o } literal en un f-string, dóblala:

value = 42
 
# Literal braces around a value
print(f"{{{value}}}")
# Output: {42}
 
# JSON-like output
key = "name"
val = "Alice"
print(f'{{"{key}": "{val}"}}')
# Output: {"name": "Alice"}
 
# Just literal braces, no interpolation
print(f"Use {{variable}} syntax in f-strings")
# Output: Use {variable} syntax in f-strings

Barras Invertidas Dentro de Expresiones

No puedes usar caracteres de barra invertida dentro de la parte de expresión {} de un f-string. Esta es una elección de diseño deliberada por legibilidad:

items = ["apple", "banana", "cherry"]
 
# This causes a SyntaxError:
# print(f"{'\\n'.join(items)}")
 
# Solution 1: assign to a variable first
newline = "\n"
print(f"{newline.join(items)}")
 
# Solution 2: use a separate operation
joined = "\n".join(items)
print(f"Items:\n{joined}")
 
# Solution 3: use chr()
print(f"{chr(10).join(items)}")

Conflictos de Comillas

Cuando tu f-string usa comillas dobles, las expresiones dentro deben usar comillas simples (o viceversa):

data = {"name": "Alice", "age": 30}
 
# Use single quotes inside when f-string uses double quotes
print(f"Name: {data['name']}, Age: {data['age']}")
 
# Or use double quotes inside when f-string uses single quotes
print(f'Name: {data["name"]}, Age: {data["age"]}')
 
# With triple quotes, you have more flexibility
print(f"""Name: {data["name"]}, Age: {data["age"]}""")

Los F-Strings No Son Constantes

Los f-strings se evalúan en tiempo de ejecución, lo que significa que no puedes usarlos como valores de argumentos predeterminados o constantes a nivel de módulo que dependan del estado en tiempo de ejecución:

# This works but evaluates at call time, not definition time
def greet(name, template=None):
    if template is None:
        template = f"Hello, {name}!"  # Evaluated here
    return template
 
# For true templates, use str.format()
TEMPLATE = "Hello, {name}! You have {count} messages."
print(TEMPLATE.format(name="Alice", count=5))

Cuidado con las Expresiones Grandes

Solo porque puedes poner cualquier expresión en un f-string no significa que debas hacerlo. Mantén las expresiones de f-string simples:

# Hard to read -- too much logic inside the f-string
result = f"{'%.2f' % (sum(x**2 for x in range(100)) / 100)}"
 
# Much better -- compute first, then format
mean_square = sum(x**2 for x in range(100)) / 100
result = f"{mean_square:.2f}"

F-Strings Raw (Crudos)

Combinar los prefijos r (raw) y f crea un f-string raw donde las barras invertidas se tratan literalmente (sin secuencias de escape) mientras las expresiones siguen siendo evaluadas:

user = "admin"
folder = "projects"
 
# Raw f-string for Windows paths
path = rf"C:\Users\{user}\{folder}\data.csv"
print(path)
# Output: C:\Users\admin\projects\data.csv
 
# Useful for regex patterns with dynamic parts
import re
prefix = "user"
pattern = rf"\b{prefix}_\d+\b"
text = "Found user_123 and user_456 in the log"
matches = re.findall(pattern, text)
print(f"Matches: {matches}")
# Output: Matches: ['user_123', 'user_456']

Tanto rf"..." como fr"..." son válidos -- el orden de los prefijos no importa.

F-Strings con Flujos de Trabajo de Ciencia de Datos

Los f-strings son invaluables en ciencia de datos para formatear salida, construir etiquetas dinámicas y crear resúmenes legibles a partir de resultados numéricos.

Formateo de Salida Numérica

import statistics
 
data = [23.4, 45.1, 31.8, 52.3, 41.7, 38.9, 29.6, 47.2]
 
mean = statistics.mean(data)
median = statistics.median(data)
stdev = statistics.stdev(data)
cv = stdev / mean  # coefficient of variation
 
print(f"Sample size:    {len(data)}")
print(f"Mean:           {mean:.2f}")
print(f"Median:         {median:.2f}")
print(f"Std deviation:  {stdev:.2f}")
print(f"CV:             {cv:.1%}")
print(f"Range:          {min(data):.1f} - {max(data):.1f}")
# Output:
# Sample size:    8
# Mean:           38.75
# Median:         40.30
# Std deviation:  9.87
# CV:             25.5%
# Range:          23.4 - 52.3

Trabajando con DataFrames de Pandas

import pandas as pd
 
df = pd.DataFrame({
    "product": ["Widget A", "Widget B", "Widget C", "Widget D"],
    "revenue": [125000, 89000, 234000, 67000],
    "units": [1250, 2100, 980, 3400],
})
 
# Summary statistics with f-strings
total_rev = df["revenue"].sum()
avg_price = (df["revenue"] / df["units"]).mean()
 
print(f"Total Revenue:  ${total_rev:>12,}")
print(f"Avg Unit Price: ${avg_price:>12,.2f}")
print(f"Products:       {len(df):>12,}")
 
# Dynamic column formatting
for _, row in df.iterrows():
    unit_price = row["revenue"] / row["units"]
    print(f"  {row['product']:<12} | Revenue: ${row['revenue']:>9,} | Units: {row['units']:>5,} | $/unit: ${unit_price:.2f}")
 
# Output:
# Total Revenue:  $     515,000
# Avg Unit Price: $       56.00
# Products:              4
#   Widget A     | Revenue: $  125,000 | Units: 1,250 | $/unit: $100.00
#   Widget B     | Revenue: $   89,000 | Units: 2,100 | $/unit: $42.38
#   Widget C     | Revenue: $  234,000 | Units:   980 | $/unit: $238.78
#   Widget D     | Revenue: $   67,000 | Units: 3,400 | $/unit: $19.71

Cuando tu análisis de datos va más allá de los resúmenes de texto y necesitas exploración interactiva, PyGWalker (opens in a new tab) puede transformar cualquier DataFrame de pandas en una visualización interactiva tipo Tableau con una sola línea de código. En lugar de formatear números manualmente para reportes estáticos, puedes arrastrar y soltar columnas para construir gráficos, aplicar filtros y explorar patrones visualmente, todo dentro de tu notebook de Jupyter.

import pandas as pd
import pygwalker as pyg
 
# After preparing your DataFrame with well-formatted columns
df = pd.DataFrame({
    "Month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
    "Revenue": [125000, 134000, 158000, 142000, 167000, 189000],
    "Growth": [0.05, 0.072, 0.179, -0.101, 0.176, 0.132],
})
 
# Add formatted columns for display
df["Revenue_Display"] = df["Revenue"].apply(lambda x: f"${x:,.0f}")
df["Growth_Display"] = df["Growth"].apply(lambda x: f"{x:+.1%}")
 
# Launch interactive visualization
# pyg.walk(df)

Formateo de Resultados de Modelos

# Formatting machine learning results
metrics = {
    "accuracy": 0.9234,
    "precision": 0.8891,
    "recall": 0.9456,
    "f1_score": 0.9164,
    "auc_roc": 0.9678,
}
 
print("Model Evaluation Results")
print("=" * 35)
for metric, value in metrics.items():
    bar_length = int(value * 20)
    bar = "#" * bar_length + "-" * (20 - bar_length)
    print(f"  {metric:<12} {value:.4f}  [{bar}]")
# Output:
# Model Evaluation Results
# ===================================
#   accuracy     0.9234  [##################--]
#   precision    0.8891  [#################---]
#   recall       0.9456  [##################--]
#   f1_score     0.9164  [##################--]
#   auc_roc      0.9678  [###################-]

Banderas de Conversión: !s, !r, y !a

Los f-strings soportan tres banderas de conversión que controlan cómo se convierte el valor de la expresión antes del formateo:

  • !s llama str() en el valor (comportamiento predeterminado)
  • !r llama repr() en el valor
  • !a llama ascii() en el valor
text = "Hello\tWorld"
name = "Caf\u00e9"
 
print(f"str:   {text!s}")
print(f"repr:  {text!r}")
print(f"ascii: {name!a}")
# Output:
# str:   Hello	World
# repr:  'Hello\tWorld'
# ascii: 'Caf\xe9'

La bandera !r es particularmente útil para depuración, ya que muestra la representación raw incluyendo comillas y caracteres de escape. Funciona muy bien junto con el especificador =.

Preguntas Frecuentes

¿Qué son los f-strings de Python y cuándo se introdujeron?

Los f-strings (literales de cadena formateadas) son un mecanismo de formateo de cadenas introducido en Python 3.6 a través de PEP 498. Permiten incrustar expresiones de Python directamente dentro de literales de cadena prefijando la cadena con f y colocando expresiones dentro de llaves. Los f-strings se evalúan en tiempo de ejecución, ofrecen la mejor legibilidad entre todas las opciones de formateo de cadenas de Python, y son más rápidos que str.format() y el formateo % porque se compilan en bytecode optimizado en tiempo de análisis.

¿Cómo formateo números con comas y decimales en f-strings?

Usa la especificación de formato después de dos puntos dentro de las llaves. Para comas como separadores de miles, usa :, -- por ejemplo, f"{1234567:,}" produce "1,234,567". Para decimales, usa :.Nf donde N es el número de dígitos -- por ejemplo, f"{3.14159:.2f}" da "3.14". Combina ambos: f"{1234.5:,.2f}" produce "1,234.50". Para porcentajes, usa :.N% que multiplica por 100 y añade un signo de porcentaje: f"{0.85:.1%}" produce "85.0%".

¿Qué es el especificador = de f-strings y cómo ayuda con la depuración?

El especificador = se añadió en Python 3.8 e imprime tanto el texto de la expresión como su valor. Escribir f"{variable=}" produce variable=valor. Esto elimina la necesidad de escribir el nombre de la variable dos veces al depurar. Funciona con cualquier expresión: f"{len(data)=}" produce len(data)=42. Puedes combinarlo con especificadores de formato: f"{price=:.2f}" produce price=49.99. Es una de las formas más rápidas de inspeccionar valores intermedios durante el desarrollo.

¿Puedo usar f-strings con cadenas multilínea?

Sí. Usa comillas triples (f"""...""" o f'''...''') para f-strings multilínea. Cada línea puede contener marcadores de posición {expresión}. Alternativamente, puedes concatenar múltiples f-strings usando concatenación implícita de cadenas colocándolos adyacentes entre paréntesis: (f"línea 1: {x}\n" f"línea 2: {y}\n"). El enfoque de comillas triples es mejor para plantillas y reportes; el enfoque de concatenación evita problemas de nueva línea inicial.

¿Son los f-strings más rápidos que str.format() y el formateo %?

Sí. Los f-strings son consistentemente el método de formateo de cadenas más rápido en Python. En benchmarks, los f-strings típicamente se ejecutan 1.5 a 2 veces más rápido que str.format() y 1.3 a 1.8 veces más rápido que el formateo %. La ventaja de velocidad proviene de la optimización en tiempo de compilación: Python convierte los f-strings directamente en bytecode eficiente en lugar de realizar búsquedas de métodos y análisis de argumentos en tiempo de ejecución. La diferencia es medible en bucles cerrados y procesamiento de datos a gran escala.

¿Cómo incluyo llaves literales en un f-string?

Dobla las llaves. Usa {{ para una { literal y }} para una } literal. Por ejemplo, f"{{value}}" produce {value} como texto plano. Para envolver un valor interpolado en llaves, usa f"{{{variable}}}" -- las llaves dobles exteriores producen llaves literales, mientras que las llaves simples interiores activan la interpolación. Esto se necesita comúnmente al generar cadenas JSON, CSS o cualquier salida que use llaves en su sintaxis.

Conclusión

Los f-strings son la forma estándar de formatear cadenas en Python moderno. Combinan la mejor legibilidad de cualquier enfoque de formateo con el mejor rendimiento, y soportan el rango completo de especificaciones de formato: precisión decimal, separadores de miles, porcentajes, notación científica, alineación, relleno, formateo de fechas y conversiones de base.

Las cosas clave a recordar:

  • Prefija con f y pon las expresiones dentro de {llaves}.
  • Usa : seguido de una especificación de formato para control preciso de la salida (:.2f, :,, :.1%, :<20).
  • Usa = después de la expresión para depuración (f"{variable=}"). Requiere Python 3.8+.
  • Escapa llaves literales doblando las llaves: {{ y }}.
  • No pongas barras invertidas dentro de la expresión {}. Asigna a una variable primero.
  • Mantén las expresiones simples. Si la lógica dentro de {} es difícil de leer, extráela.
  • Usa .format() solo cuando necesites plantillas reutilizables almacenadas como variables.

Los f-strings manejan todo desde la depuración rápida con print() hasta la generación de reportes de producción. Una vez que los adoptes, no hay razón para volver a métodos de formateo más antiguos. Ya sea que estés construyendo pipelines de datos, formateando salidas de modelos de ML o generando reportes financieros, los f-strings entregan código limpio, rápido y legible.

📚