Formatear cadenas con Python

    Introducci贸n

    Tarde o temprano, el formateo de cadenas se convierte en un mal necesario para la mayor铆a de los programadores. M谩s a煤n en el pasado, antes de la era de la GUI de cliente pesado, pero la necesidad de tener una representaci贸n de cadena espec铆fica sigue siendo un caso de uso bastante com煤n. Mi primera introducci贸n fue en la universidad cuando ten铆a un profesor de la vieja escuela que ten铆a un amor impuro por hacernos escribir aplicaciones de consola Java con especificaciones neur贸ticas para generar con el printf(...) funci贸n. Una cosa que se mantuvo as铆 entonces y que todav铆a lo es ahora es que la documentaci贸n para el formateo de cadenas (pr谩cticamente para todos los idiomas) deja mucho que desear. Espero aliviar este dolor hoy escribiendo sobre c贸mo lograr el formateo de cadenas en Python.

    En Python hay varias t茅cnicas para formatear cadenas, cuatro para ser exactos. Curiosamente, esto va en contra de la mentalidad de Python de que, en general, deber铆a haber una mejor manera clara de realizar una tarea. Sin embargo, si ha pasado una cantidad de tiempo razonable con el lenguaje, probablemente haya visto esta variedad de t茅cnicas dispares y se haya preguntado, “驴cu谩l es el problema con todo esto?”.

    Revisi贸n de las t茅cnicas de formato de cuatro cadenas

    Comencemos con el m茅todo m谩s com煤n que utiliza el % operador. Digo el m谩s com煤n simplemente porque ha existido por m谩s tiempo y lo ves por todas partes (libros, publicaciones de blog, Stack Overflow, etc.). Para utilizar este m茅todo, especifica un marcador de posici贸n en una cadena usando %s para Strings y %d para los n煤meros.

    >>> "Hello reader, welcome to the %s form of string formatting." % 'modulus'
    'Hello reader, welcome to the modulus form of string formatting.'
    >>>
    >>> "Formatting multiple (%d, %d, %d, ...) values requires a %s." % (1, 2, 3, 'tuple')
    'Formatting multiple (1, 2, 3, ...) values requires a tuple.'
    >>>
    >>> print("""If you prefer named placeholders for values %(one)d, %(two)d,
    ... %(three)d ... you can use a dict""" % {'one':1, 'two':2, 'three':3})
    If you prefer named placeholders for values 1, 2,
    3 ... you can use a dict
    

    La siguiente t茅cnica a cubrir es la str.format(...) m茅todo. Este estaba destinado a ser el reemplazo de la % estilo mostrado anteriormente. Esta t茅cnica utiliza las llaves {} designador para especificar d贸nde y c贸mo formatear un valor en una cadena.

    >>> "Hello reader, welcome to the {} form of string formatting".format('str.format(...)')
    'Hello reader, welcome to the str.format(...) form of string formatting'
    >>>
    >>> print("""Formatting multiple ({0}, {1}, {2}, ...) values requires  
    ... that you use multiple {3} brackets and optionally specify ordering
    ... values.""".format(1,2,3,'{}'))
    Formatting multiple (1, 2, 3, ...) values requires  
    that you use multiple {} brackets and optionally specify ordering
    values.
    >>>
    >>> print("""The {language} str.format() method also allows you to use
    ... named parameters which help keep code {adjective}
    ... """.format(language="Python", adjective="concise"))
    The Python str.format() method also allows you to use
    named parameters which help keep code concise
    

    Luego est谩 la t茅cnica de la plantilla de cadena, que es una clase en el m贸dulo de String. Este m茅todo de formateo de cadenas es un poco m谩s detallado y no admite especificadores de tipo (s, d, f, etc.), a diferencia de los dos anteriores. Con esta t茅cnica, especifica el marcador de posici贸n en una cadena prefijando el valor deseado con un $ en el constructor del Template(...) clase, luego llamas a un substitute(...) en el objeto instanciado con un par谩metro con nombre. Este m茅todo es mucho menos com煤n debido a su menor potencia y flexibilidad.

    >>> from string import Template
    >>> tmpl = Template("Hello my name is $name")
    >>> tmpl.substitute(name="Adam")
    'Hello my name is Adam'
    

    La 煤ltima t茅cnica, y la implementaci贸n m谩s reciente que solo est谩 disponible en Python 3.6, se conoce como interpolaci贸n de Strings. Esto tiene similitudes con la cadena de plantilla Javascript ES6. Las interpolaciones de cadenas requieren que el literal de cadena tenga un prefijo f"" y permite que tanto las expresiones como las variables se especifiquen directamente dentro de la cadena siempre que est茅n rodeadas por {} soportes.

    >>> method="String Interpolation"
    >>> f"Hello reader, I am the {method} of formatting"
    'Hello reader, I am the String Interpolation of formatting'
    >>>
    >>> f"With this method you can have expressions like {{1 + 1}} = {1 + 1}"
    'With this method you can have expressions like {1 + 1} = 2'
    

    Profundizando en el formato de cadenas

    En las siguientes secciones voy a restringir la discusi贸n solo a los str.format() m茅todo y f"" t茅cnica de interpolaci贸n, ya que son los m茅todos preferidos para formatear cadenas. Los temas en los que me gustar铆a profundizar incluyen:

    • Alineaci贸n del texto
    • Formateo de n煤meros
    • Conversiones de tipos

    Ambos str.format() y las t茅cnicas de interpolaci贸n comparten la misma sintaxis para definir el formato entre {} soportes que hacen uso del : para separar los identificadores con nombre u ordinales a la izquierda y las especificaciones de formato a la derecha.

    Alineaci贸n del texto

    Puede alinear valores dentro de una longitud de texto especificada utilizando el <, >o ^ s铆mbolos para especificar alineaci贸n a la izquierda, alineaci贸n a la derecha o centrado, respectivamente. Luego, siga esos s铆mbolos con el ancho de car谩cter que desee.

    Python> 2.6:

    >>> left_aligned = "Left Align"
    >>> center = "Centered"
    >>> right_aligned = "Right Align"
    >>> "{left_aligned:<15}{center:^10}{right_aligned:>15}".format(
    ...     left_aligned=left_aligned,
    ...     center=center,
    ...     right_aligned=right_aligned)
    'Left Align      Centered     Right Align'
    

    Tambi茅n puede especificar las posiciones ordinales en lugar de palabras clave.

    >>> "{1:<15}{0:^10}{2:>15}".format(center, left_aligned, right_aligned)
    'Left Align      Centered     Right Align'
    

    O puede omitirlos si el orden de los par谩metros para format(...) son del mismo orden del {}.

    >>> "{:<15}{:^10}{:>15}".format(left_aligned, center, right_aligned)
    'Left Align      Centered     Right Align'
    

    Python 3.6:

    >>> f"{left_aligned:<15}{center:^10}{right_aligned:>15}"
    'Left Align      Centered     Right Align'
    

    En los ejemplos anteriores, llen茅 impl铆citamente el espacio acolchado restante con espacios en blanco, que es el comportamiento predeterminado. Sin embargo, si esto no es lo que desea, puede completarlos con algo diferente especificando un car谩cter inmediatamente despu茅s de los dos puntos.

    Python> 2.6:

    >>> "{:><15}|{:-^10}|{:<>15}".format(left_aligned, center, right_aligned)
    'Left Align>>>>>|-Centered-|<<<<Right Align'
    

    Python 3.6:

    >>> f"{left_aligned:><15}{center:-^10}{right_aligned:<>15}"
    'Left Align>>>>>-Centered-<<<<Right Align'
    

    N煤meros

    Dar formato a n煤meros de coma flotante, aquellos que contienen posiciones decimales, es pan comido en Python. Todo lo que necesita hacer es seguir los dos puntos con un f.

    Python> 2.6:

    >>> rounded_pi = 3.14
    >>> "A rounded representation of Pi {:f}".format(rounded_pi)
    'A rounded representation of Pi 3.140000'
    

    Python 3.6:

    >>> f"A rounded representation of Pi {rounded_pi:f}"
    'A rounded representation of Pi 3.140000'
    

    Observe que la cadena tiene seis lugares decimales. Esto se debe a que, de forma predeterminada, el especificador flotante tiene seis lugares que rellenar谩 con ceros o redondear谩 para contener solo seis, seg煤n la entrada. Por ejemplo, si importo la constante pi m谩s larga del m贸dulo matem谩tico, ver谩 el redondeo en acci贸n.

    Python> 2.6:

    >>> from math import pi
    >>> pi
    3.141592653589793
    >>> "A rounded representation of Pi {:f}".format(pi)
    'A rounded representation of Pi 3.141593'
    

    Python 3.6:

    >>> f"A rounded representation of Pi {pi:f}"
    'A rounded representation of Pi 3.141593'
    

    Para especificar una precisi贸n diferente (n煤mero de posiciones decimales) simplemente preceda al f por el n煤mero de lugares decimales deseado como tal.

    Python> 2.6:

    >>> "A rounded representation of Pi {:.3f}".format(pi)
    'A rounded representation of Pi 3.142'
    

    Python 3.6:

    >>> f"A rounded representation of Pi {pi:.3f}"
    'A rounded representation of Pi 3.142'
    

    Otro caso de uso de formato para n煤meros de punto flotante es el especificador de porcentaje. Esto funciona convirtiendo lo que se espera que sea una proporci贸n o raz贸n (0-1) a un valor de 100 y trata la porci贸n decimal sobrante de manera similar a la f especificador con una precisi贸n predeterminada de seis.

    Python> 2.6:

    >>> receptions = 17
    >>> passes = 29
    >>> "The completion percentage is {:.2%}".format(receptions/passes)
    'The completion percentage is 58.62%'
    

    Python 3.6:

    >>> f"The completion percentage is {receptions/passes:.2%}"
    'The completion percentage is 58.62%'
    

    Ok, eso se ocupa de la mayor铆a de los casos de uso que involucran n煤meros de punto flotante, pero 驴qu茅 pasa con los n煤meros grandes? Python tambi茅n tiene soporte para formatearlos colocando comas para aumentar la legibilidad de n煤meros grandes. Para aprovechar esto, simplemente coloque un , despu茅s del colon.

    Python> 2.6:

    >>> house_price = 299999.99
    >>> "The price of the house is ${:,}".format(house_price)
    'The price of the house is $299,999.99'
    

    Python 3.6:

    >>> f"The price of the house is ${house_price:,}"
    'The price of the house is $299,999.99'
    

    Conversiones de tipo

    Las conversiones de tipos son un caso de uso un poco menos com煤n, pero surgen de vez en cuando. Las conversiones de tipos principales son las siguientes para los n煤meros:

    Descripci贸n de conversi贸n

    segundoBinario
    oOctal
    XHexadecimal
    reDecimal

    Al igual que con los otros especificadores de formato, funcionan agreg谩ndolos despu茅s de los dos puntos. Con suerte, este patr贸n general de sintaxis de formato se est谩 volviendo claro para usted.

    Python> 2.6:

    >>> number = 157
    >>> print("Binary: {:b}nOctal {:o}nHexadecimal: {:x}nDecimal: {:d}".format(
    ...     number,
    ...     number,
    ...     number,
    ...     number))
    Binary: 10011101
    Octal 235
    Hexadecimal: 9d
    Decimal: 157
    

    Python 3.6:

    >>> print(f"Binary: {number:b}nOctal {number:o}nHexadecimal: {number:x}nDecimal: {number:d}")
    Binary: 10011101
    Octal 235
    Hexadecimal: 9d
    Decimal: 157
    

    Conclusi贸n

    En este breve tutorial sobre el formato de cadenas, apenas he ara帽ado la superficie, pero espero haber podido dar algunos ejemplos concretos de casos de uso comunes con los que es probable que se encuentre en sus programas diarios de Python. Mi objetivo ha sido proporcionar una explicaci贸n b谩sica de la sintaxis del formato de cadenas y las t茅cnicas de implementaci贸n. A partir de aqu铆, debe tener la suficiente comprensi贸n para profundizar en los detalles de la documentaci贸n. Gracias por leer y comentar a continuaci贸n.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *