Tracks
/
Python
Python
/
Temario
/
Formato de strings
Fo

Formato de strings en Python

1 ejercicio

Acerca de Formato de strings

Formateo de strings en Python

El formateo de strings es el proceso de convertir valores en strings e insertarlos en una plantilla de string. El Zen de Python afirma que debería haber «una forma obvia de hacer algo en Python». Pero cuando se trata del formateo de strings, las cosas son un poco... menos zen.

Puede sorprender descubrir que hay cuatro formas principales de hacer formateo de strings en Python, cada una para un escenario diferente. Parte de esto se debe a la larga historia de Python, y parte a consideraciones como la internacionalización o la sanitización de la entrada. Empezaremos con las adiciones más recientes a la caja de herramientas del formateo de strings y avanzaremos hacia atrás hasta el formateo de strings «estilo antiguo» o «estilo printf()».

Interpolación literal de strings: el f-string

Introducidos en Python 3.6, los f-strings (abreviatura de «formatted strings») o la interpolación literal de strings son una forma de evaluar (y formatear) expresiones y strings de manera rápida y eficiente a un tipo str, usando el prefijo f (o F) antes de las comillas (así: f'{object}').

Los f-strings se pueden usar con todos los tipos de string que los encierran, como los de una sola línea (' o ") y los de varias líneas (''' o """). Cualquier variable, expresión u otro tipo colocado dentro de las {} se evalúa primero, luego se convierte a un str y, por último, se concatena con cualquier str que esté fuera de las llaves.

En este ejemplo, insertamos dos valores de variables en una oración (un str y un float):

>>> name = 'eighth'
>>> value = 1/8

# The f-string, using the two values.
# The .2f format code truncates, so the value displays as 0.12.
>>> f'An {name} is approximately {value:.2f}.'
'An eighth is approximately 0.12.'

Las expresiones evaluadas pueden ser casi cualquier cosa. Algunas de las (amplias) posibilidades que se pueden evaluar: strs, números, variables, expresiones aritméticas, expresiones condicionales, tipos integrados, slices, funciones, lambdas, comprensiones, o cualquier objeto que tenga definido el método __str__ o __repr__.

De lo simple a lo complejo:

Insertar una variable: el uso más simple de un f-string es colocar una variable directamente en el string.

# Assigning a variable.
>>> name = "World"

# Inserting that variable.
>>> f'Hello, {name}!'
'Hello, World!'

Expresiones dentro de {}: cualquier expresión de Python válida se puede evaluar dentro de las llaves. Ten en cuenta que usar comillas dobles dentro de un f-string entre comillas simples (o al revés) evita la necesidad de secuencias de escape:

# A dictionary of key:value pairs.
>>> waves = {'water': 1, 'light': 3, 'sound': 5}

# Inserting the whole dict.
>>> f'Wave ranks: {waves}'
"Wave ranks: {'water': 1, 'light': 3, 'sound': 5}"

# An expression can be evaluated inline:
>>> f"Tenfold the value of 'light' is {waves['light'] * 10}."
"Tenfold the value of 'light' is 30."

# A method call can also be evaluated inline:
>>> f'{"hello world!".title()} is a classic greeting.'
'Hello World! is a classic greeting.'

# An f-string can be nested inside another f-string:
>>> f"{f'hello world!'.title()} is a classic greeting."
'Hello World! is a classic greeting.'

Formateo de la salida: el mini-lenguaje de especificación de formato se puede usar para controlar la alineación, la precisión numérica y mucho más. La especificación de formato va después del valor, separada por :.

# Right-align a value to ten characters, and round it to 3 decimal places.
>>> value = 1 / 7
>>> f'One seventh is {value:10.3f}.'
'One seventh is      0.143.'

# A format specification can be set using variables as well.
>>> padding = 10
>>> precision = 3
>>> f'One seventh is {value:{padding}.{precision}f}.'
'One seventh is      0.143.'

Todo junto: variables, expresiones, llamadas a funciones y formateo de la salida:

>>> precision = 3
>>> f"{30e8 * 111_000:6.{precision}e}"
'3.330e+14'

>>> verb = 'meet'
>>> the_end = ['end', 'of', 'transmission']
>>> f'"Have a {"NICE".lower()} day, I will {verb} you after {30e8 * 111_000:6.{precision}e} light-years."{the_end}'
'"Have a nice day, I will meet you after 3.330e+14 light-years."[\'end\', \'of\', \'transmission\']'

# Did you notice the escaped single-quotes in the previous example?
# Using double quotes instead of single quotes for the f-string means the list's single-quoted strings print cleanly.
>>> f"Have a nice day. {the_end}"
"Have a nice day. ['end', 'of', 'transmission']"

Hay dos limitaciones principales que debes tener en cuenta. Las expresiones de f-string no pueden estar vacías. Además, antes de Python 3.12, no podían contener comentarios.

>>> f"An empty expression will error: {}"
SyntaxError: f-string: empty expression not allowed

>>> word = 'word'
>>> f"""A comment in a triple quoted f-string: {
    word # I chose a nice variable
}"""
'A comment in a triple quoted f-string: word'
Caution

La interpolación de strings no se puede usar junto con la API de GNU gettext para la internacionalización (I18N) y la localización (L10N), por lo que se recomienda usar la clase string.Template o el método str.format() que se describen a continuación en lugar de un f-string en cualquier escenario de traducción de «envoltura de strings».

También ten en cuenta que usar expresiones dentro de las llaves {} del f-string es similar a usar eval() o exec(), así que no es muy seguro y nunca debería usarse con la entrada del usuario.

El método str.format()

El método str.format() reemplaza los marcadores de posición dentro del string con valores que se pasan como argumentos a la función. Los marcadores de posición se identifican con nombres ({price}), números ({0} o índices), o incluso con marcadores vacíos (posicionales) {}.

Por ejemplo:

# A named placeholder and a positional placeholder.
>>> 'My text: {placeholder_1} and {}.'.format(12, placeholder_1='named placeholder')
'My text: named placeholder and 12.'

Al igual que con los f-strings, el método str.format() de Python admite toda una gama de especificadores de formato del mini-lenguaje que se pueden usar para alinear texto, truncar números de punto flotante y más.

El patrón completo de un especificador de formato es {[<name>][!<conversion>][:<format_specifier>]}:

Ejemplo de conversiones para una letra diacrítica:

# Fills in the object at index zero, converted to a string.
>>> 'An e with an umlaut: {0!s}'.format('ë')
'An e with an umlaut: ë'


# Fills in the object at index zero, converted to a repr.
>>> 'An e with an umlaut (object representation): {0!r}'.format('ë')
"An e with an umlaut (object representation): 'ë'"


# Fills in the object at index zero, converted to ASCII.
>>> 'An e with an umlaut converted into ASCII: {0!a}'.format('ë')
"An e with an umlaut converted into ASCII: '\xeb'"


# Fills in the object in the first position,
# then fills in the object in the second position formatted as a repr.
>>> 'She said her name is not {} but {!r}.'.format('Chloe', 'Zoë')
"She said her name is not Chloe but 'Zoë'."

Ejemplos de especificadores de formato comunes:

# Integer and binary/hex representations of the same number.
>>> my_num = 42
>>> f"{my_num} in binary is {my_num:b}. In hex, it is {my_num:x}"
"42 in binary is 101010. In hex, it is 2a"

# Alignment: left (<), right (>), and center (^) using up to ten characters total.
>>> f"[{"left":<10}] [{"right":>10}] [{"center":^10}]"
"[left      ] [     right] [  center  ]"

# Float precision and scientific notation (up to three decimal places).
>>> pi = 3.141592653589793
>>> f"Fixed: {pi:.3}  Scientific: {pi:.3e}"
"Fixed: 3.142  Scientific: 3.142e+00"

# Thousands separator and percentage.
>>> balance = 1000
>>> rate = 0.0225
>>> f"Balance: ${balance:,.0f}  Interest rate: {rate:.1%}"
"Balance: $1,000  Interest rate: 2.2%"

# Putting it all together:
>>> items = [("Widget", 1250, 9.991), ("Gadget", 37, 24.503), ("Doohickey", 4, 149.002)]
>>> header = f"{"Item":<12} {"Qty":>6} {"Price":>9}"
>>> print(header)
Item            Qty     Price
>>> for name, qty, price in items:
...     print(f"{name:<12} {qty:>6} {price:>9.2f}")
Widget         1250      9.99
Gadget           37     24.50
Doohickey         4    149.00

Puedes ver más ejemplos al final de esta documentación.

Formateo con %, o formateo al estilo printf()

Usar el operador % para formatear es el método más antiguo de formateo de strings en Python. Proviene del lenguaje C y permite usar argumentos posicionales para construir un str.

Este método fue reemplazado tanto por los f-strings como por str.format(), y por eso el apodo del formateo con % es «estilo antiguo». Todavía se puede encontrar en Python 2 o en código heredado. Aunque usar este método funciona en Python 3.x, por lo general se evita el formateo con % porque puede ser propenso a errores, es menos eficiente, tiene menos opciones disponibles y cualquier desajuste entre un marcador de posición y su argumento puede generar una excepción. Usar el operador % es similar a printf(), por lo que a veces también se le llama formateo printf.

# Assigning a variable.
>>> name = "Anna-conda"

# Building a string using %.
>>> "The snake's name is %s." % name
"The snake's name is Anna-conda."

En el ejemplo anterior, el operador % sustituye el marcador de posición %s por la variable name en tiempo de ejecución. Si quieres agregar varias variables a un string, debes proporcionar una tupla que contenga un objeto por cada marcador de posición después del %:

# Assigning variables.
>>> name = "Billy the Kid"
>>> fruit = "grapes"

# Building a string using %.
>>> "Surprisingly, %s's favorite snack was %s." %(name, fruit)
"Surprisingly, Billy the Kid's favorite snack was grapes."

Strings de plantilla

string.Template() (que no debe confundirse con los t-strings de Python 3.14) es una clase del módulo string (a diferencia del tipo str integrado), que forma parte de la biblioteca estándar de Python, pero que hay que importar para usarla. Los strings de plantilla admiten sustitución basada en $ y son mucho más simples y menos potentes que las otras opciones mencionadas aquí. Sin embargo, pueden ser muy útiles para la internacionalización complicada o para sanitizar entradas externas.

Se considera que string.Template es más seguro para la entrada de usuario no confiable porque evita la evaluación de expresiones arbitrarias o el acceso a atributos de objetos, lo que mitiga los ataques de inyección de strings de formato.

>>> from string import Template

>>> name = "Anna-Conda"

# Creating a Template with placeholder text.
>>> template_string = Template("The snake called `$snake_name` has escaped!")

# Calling .substitute() to replace the placeholder with a value.
>>> template_string.substitute(snake_name=name)
'The snake called `Anna-Conda` has escaped!'

Puedes encontrar más información sobre string.Template en la documentación de Python.

¿Cómo eliges qué método de formateo usar?

Con todas estas opciones y mini-lenguajes, ¿cómo decides cuál usar cuando formateas strings en Python? Aquí tienes algunas pautas rápidas:

  1. Los f-strings son los más nuevos y los más fáciles de leer. Si no necesitas internacionalizar, deberían ser el método preferido para Python 3.6+.

  2. str.format() es versátil, potente y compatible tanto con gnu gettext como con la mayoría de las versiones de Python.

  3. Si lo que necesitas es simplicidad, seguridad o mucha internacionalización, puedes usar string.Template() para mitigar riesgos cuando haya que manejar entradas de usuarios, y también para envolver strings de traducción.

  4. Por lo general, se considera que el operador % está obsoleto para código nuevo, aunque todavía funciona en Python moderno. En su mayoría, debería usarse para la compatibilidad con bases de código más antiguas. El formateo con % es más propenso a errores (y tiene menos funcionalidad) que otros métodos, y puede generar problemas al mostrar caracteres no ASCII. Consulta tu distribución específica de Python para ver los detalles de compatibilidad si piensas usarlo.

Si quieres ir más allá, todo sobre el formateo y las buenas prácticas de formateo de strings en Python son buenos puntos de partida.

Editar en GitHub El enlace se abre en una ventana o pestaña nueva