Las muchas formas de formateo de cadenas de Python: ¿las más antiguas (van a quedar) obsoletas?

106

Python tiene al menos seis formas de formatear una cadena:

In [1]: world = "Earth"

# method 1a
In [2]: "Hello, %s" % world
Out[2]: 'Hello, Earth'

# method 1b
In [3]: "Hello, %(planet)s" % {"planet": world}
Out[3]: 'Hello, Earth'

# method 2a
In [4]: "Hello, {0}".format(world)
Out[4]: 'Hello, Earth'

# method 2b
In [5]: "Hello, {planet}".format(planet=world)
Out[5]: 'Hello, Earth'

# method 2c
In [6]: f"Hello, {world}"
Out[6]: 'Hello, Earth'

In [7]: from string import Template

# method 3
In [8]: Template("Hello, $planet").substitute(planet=world)
Out[8]: 'Hello, Earth'

Una breve historia de los diferentes métodos:

  • printfel formato de estilo ha existido desde la infancia de Pythons
  • La Templateclase se introdujo en Python 2.4
  • El formatmétodo se introdujo en Python 2.6
  • f-las cadenas se introdujeron en Python 3.6

Mis preguntas son:

  • ¿El printfformato de estilo está obsoleto o va a quedar obsoleto?
  • En el Template class, ¿el substitutemétodo está obsoleto o va a quedar obsoleto? (No estoy hablando de lo safe_substituteque, según tengo entendido, ofrece capacidades únicas)

Preguntas similares y por qué creo que no son duplicados:

  • Formato de cadena de Python:% vs. .format : trata solo los métodos 1 y 2, y pregunta cuál es mejor; mi pregunta es explícitamente sobre la desaprobación a la luz del Zen de Python

  • Opciones de formato de cadena: pros y contras : trata solo los métodos 1a y 1b en la pregunta, 1 y 2 en la respuesta, y tampoco nada sobre la desaprobación

  • formato de cadena avanzado frente a cadenas de plantilla , principalmente sobre los métodos 1 y 3, y no aborda la obsolescencia

  • Expresiones de formato de cadena (Python) : la respuesta menciona que se planea que el enfoque original '%' sea obsoleto . Pero, ¿cuál es la diferencia entre la desaprobación planificada , la desaprobación pendiente y la desaprobación real ? Y el printfmétodo -style no genera ni siquiera a PendingDeprecationWarning, entonces, ¿realmente va a quedar obsoleto? Esta publicación también es bastante antigua, por lo que la información puede estar desactualizada.

Ver también

gerrit
fuente
1
¿Debo señalar que olvidó la Formatterclase?
Martijn Pieters

Respuestas:

14

Si bien hay varias indicaciones en los documentos de que .formatlas cadenas de f son superiores a las %cadenas, no hay un plan sobreviviente para desaprobar este último.

En el problema de confirmación # 14123: mencione explícitamente que el formato de cadena de% de estilo antiguo tiene salvedades, pero que no desaparecerá pronto. , inspirado en el problema Indique que no hay planes actuales para desaprobar el formato de estilo printf , los documentos sobre %-formatting fueron editados para contener esta frase:

Como la nueva sintaxis de formato de cadena es más flexible y maneja tuplas y diccionarios de forma natural, se recomienda para código nuevo. Sin embargo, no hay planes actuales para desaprobar el formato de estilo printf .

(El énfasis es mío.)

Esta frase se eliminó más tarde, en la confirmación Close # 4966: renovar los documentos de secuencia para explicar mejor el estado de Python moderno . Esto puede parecer una señal de que un plan para desaprobar el %formato estaba de vuelta en las cartas ... pero sumergirse en el rastreador de errores revela que la intención era la opuesta. En el rastreador de errores, el autor de la confirmación caracteriza el cambio de esta manera :

  • cambió la prosa que describe la relación entre el formato de estilo printf y el método str.format (eliminando deliberadamente la implicación de que el primero es un peligro real de desaparecer; simplemente no es práctico para nosotros contemplar seriamente la posibilidad de eliminarlo)

En otras palabras, hemos tenido dos cambios consecutivos en los %documentos de formato destinados a enfatizar explícitamente que no se desaprobará, y mucho menos se eliminará. Los documentos siguen opinando sobre los méritos relativos de los diferentes tipos de formato de cadena, pero también tienen claro que el %formato no quedará obsoleto ni se eliminará.

Además, el cambio más reciente a ese párrafo , en marzo de 2017, lo cambió de este ...

Las operaciones de formateo descritas aquí exhiben una variedad de peculiaridades que conducen a una serie de errores comunes (como no mostrar correctamente las tuplas y los diccionarios). El uso de los literales de cadena formateados más nuevos o la str.formatinterfaz ayuda a evitar estos errores. Estas alternativas también proporcionan enfoques más potentes, flexibles y extensibles para dar formato al texto.

... a esto:

Las operaciones de formateo descritas aquí exhiben una variedad de peculiaridades que conducen a una serie de errores comunes (como no mostrar correctamente las tuplas y los diccionarios). El uso de literales de cadena con formato más reciente, la str.formatinterfaz o las cadenas de plantilla pueden ayudar a evitar estos errores. Cada una de estas alternativas ofrece sus propias ventajas y desventajas de simplicidad, flexibilidad y / o extensibilidad.

Observe el cambio de "ayuda a evitar" a "puede ayudar a evitar", y cómo la clara recomendación de .formaty las cuerdas de f se han reemplazado por una prosa ambigua y equívoca sobre cómo cada estilo "proporciona sus propias compensaciones y beneficios" . Es decir, no solo una desaprobación formal ya no está en las tarjetas, sino que los documentos actuales reconocen abiertamente que el %formateo al menos tiene algunos "beneficios" sobre los otros enfoques.

De todo esto inferiría que el movimiento para desaprobar o eliminar el %formato no solo ha fallado, sino que ha sido derrotado completa y permanentemente.

Mark Amery
fuente
2
El suave cambio de idioma se agregó para aplacar a los mantenedores de Mercurial (entre otros) que no querían que Mercurial se quedara atrás con una base de código demasiado grande para erradicar su uso %. Ahora que se ha eliminado la política de "no modificar códigos a gran escala", sus objeciones también se están desvaneciendo. A la larga, el mantenimiento de ambos formularios sin beneficios restantes, ya que % en algún momento la sintaxis printf se eliminará de todos modos. Simplemente no sabemos cuándo todavía, por lo que valió la pena bajar el tono del lenguaje.
Martijn Pieters
@MartijnPieters Interesante. Parece que tiene mucho conocimiento sobre esta decisión que me falta. Por lo que vale, creo que una respuesta bien referenciada que describa estos puntos (ya sea como una nueva respuesta o una edición de la existente) tendría valor.
Mark Amery
58

El nuevo .format()método está destinado a reemplazar la %sintaxis de formato anterior. A este último se le ha quitado el énfasis (pero aún no se ha desaprobado oficialmente ). La documentación del método dice tanto:

Este método de formateo de cadenas es el nuevo estándar en Python 3, y debería preferirse al %formato descrito en Operaciones de formato de cadenas en código nuevo.

(Énfasis mío).

Para mantener la compatibilidad con versiones anteriores y facilitar la transición, el formato anterior se ha dejado en su lugar por ahora . De la propuesta PEP 3101 original :

Compatibilidad al revés

La compatibilidad con versiones anteriores se puede mantener dejando los mecanismos existentes en su lugar. El nuevo sistema no choca con ninguno de los nombres de método de las técnicas de formateo de cadenas existentes, por lo que ambos sistemas pueden coexistir hasta que llegue el momento de desaprobar el sistema anterior.

Tenga en cuenta el hasta que llegue el momento de desaprobar el sistema anterior ; no ha quedado obsoleto, pero el nuevo sistema se utilizará siempre que escriba código nuevo .

El nuevo sistema tiene la ventaja de que puede combinar el enfoque de tupla y diccionario del antiguo %formateador:

"{greeting}, {0}".format(world, greeting='Hello')

y es extensible a través del object.__format__()enlace utilizado para manejar el formato de valores individuales.

Tenga en cuenta que el sistema anterior tenía %y la Templateclase, donde este último le permite crear subclases que agregan o alteran su comportamiento. El sistema de nuevo estilo tiene la Formatterclase para llenar el mismo nicho.

Python 3 se ha alejado aún más de la obsolescencia, en lugar de darle una advertencia en la sección de printfformato de cadena de estilo :

Nota : Las operaciones de formato descritas aquí presentan una variedad de peculiaridades que conducen a una serie de errores comunes (como no mostrar correctamente las tuplas y los diccionarios). El uso de los literales de cadena formateados más nuevos o la str.format()interfaz ayuda a evitar estos errores. Estas alternativas también proporcionan enfoques más potentes, flexibles y extensibles para dar formato al texto.

Python 3.6 también agregó literales de cadena formateados , que integran las expresiones en las cadenas de formato. Este es el método más rápido para crear cadenas con valores interpolados y debe usarse en lugar de str.format()donde se pueda usar un literal.

Martijn Pieters
fuente
4
Y con Formatterpuedes crear formatos personalizados como los que datetimeusan los objetos. Además, dado que .formates una función, puede usarla para crear formato perezoso invocable de forma más directa: por ejemplo,fmt = '{} - {}'.format; fmt(a, b)
Jon Clements
No veo cómo Templatese relaciona con %o con el sistema antiguo . En particular, el PEP que vincula estados Si bien existe cierta superposición entre esta propuesta y string.Template, se considera que cada uno responde a una necesidad distinta, y que uno no obvia al otro. En su respuesta, uno puede estar confundido de que el Templateformateo, al ser parte del sistema anterior , también está obsoleto.
Bakuriu
@Bakuriu: Bien, creo que me perdí esa parte; pero en mi opinión la Formatterclase puede cubrir las mismas necesidades que string.Template().
Martijn Pieters
1
[...]should be preferred to the % formatting[...]esta parte se ha eliminado de la documentación. docs.python.org/3/library/stdtypes.html#str.format
AXO
Creo que esta respuesta actualmente es engañosa; el primer pasaje citado se ha eliminado de los documentos de Python 3, y me parece bastante claro que no queda ninguna intención de que se produzca una desaprobación. Esta respuesta todavía tiene valor histórico, pero me inclinaría a modificar la redacción para evitar cualquier sugerencia de que todavía hay una desaprobación en las cartas, y editar gran parte de la primera mitad de la respuesta para que esté en tiempo pasado. Lo haré yo mismo en algún momento si no se opone, pero pensé en comentar primero para darle la oportunidad de hacer esos cambios usted mismo si lo desea.
Mark Amery
45

El %operador para el formato de cadena no está obsoleto y no se eliminará, a pesar de las otras respuestas.
Cada vez que se plantea el tema en la lista de desarrollo de Python, existe una fuerte controversia sobre cuál es mejor, pero no hay controversia sobre si eliminar la forma clásica: se mantendrá. A pesar de estar indicado en PEP 3101, Python 3.1 había aparecido y desaparecido, y el %formato todavía existe.

Las afirmaciones para mantener el estilo clásico son claras: es simple, es rápido, es rápido para hacer cosas cortas. Usar el .formatmétodo no siempre es más legible, y casi nadie, incluso entre los desarrolladores principales, puede usar la sintaxis completa proporcionada por .formatsin tener que mirar la referencia. Incluso en 2009, uno tenía mensajes como este: http: // mail. python.org/pipermail/python-dev/2009-October/092529.html : el tema apenas había aparecido en las listas desde entonces.

Actualización de 2016

En la versión actual de desarrollo de Python (que se convertirá en Python 3.6), existe un tercer método de interpolación de cadenas, descrito en PEP-0498 . Define un nuevo prefijo de cita f""(además del actual u"", b""y r"").

El prefijo de una cadena fllamará a un método en el objeto de cadena en tiempo de ejecución, que interpolará automáticamente las variables del alcance actual en la cadena:

>>> value = 80
>>> f'The value is {value}.'
'The value is 80.'
jsbueno
fuente
3
Es mucho más agradable permitir que los tipos implementen los suyos __format__. Por ejemplo, format(Decimal('0.1'), '.20f')vs '%.20f' % Decimal('0.1'). Este último convierte el decimal en un flotador.
Eryk Sun
2
NÓTESE BIEN. No discutí que el estilo antiguo es mejor en todos los aspectos, solo que es más corto y, a veces, más legible (y otras veces no). Ciertamente, la nueva forma es mucho más flexible.
jsbueno
¿Existe un equivalente fen Python 3?
Daniel
Los f-stringsque se usan arriba son una nueva característica en el lenguaje a partir de Python 3.6. No existe en versiones anteriores y generará un error de sintaxis en ellas.
jsbueno
20

La última posición de Guido sobre esto parece indicarse aquí:

Novedades de Python 3.0

PEP 3101: un nuevo enfoque para el formato de cadenas

Un nuevo sistema para operaciones de formateo de cadenas integradas reemplaza al operador de formato de cadena%. (Sin embargo, el operador% todavía se admite; quedará obsoleto en Python 3.1 y se eliminará del lenguaje en algún momento posterior). Lea PEP 3101 para obtener la primicia completa.

Y el PEP3101 en sí, que tiene la última modificación que se remonta al (viernes, 30 de septiembre de 2011), por lo que no hay progreso últimamente en ese, supongo.

GSP
fuente
18

Al observar los documentos de Python más antiguos y PEP 3101, se dijo que el operador% quedará obsoleto y se eliminará del lenguaje en el futuro. La siguiente declaración estaba en los documentos de Python para Python 3.0, 3.1 y 3.2:

Dado que str.format () es bastante nuevo, una gran cantidad de código Python todavía usa el operador%. Sin embargo, debido a que este antiguo estilo de formateo eventualmente será eliminado del lenguaje, generalmente se debe usar str.format ().

Si va a la misma sección en los documentos de Python 3.3 y 3.4, verá que esa declaración ha sido eliminada. Tampoco puedo encontrar ninguna otra declaración en ningún otro lugar de la documentación que indique que el operador quedará obsoleto o se eliminará del idioma. También es importante señalar que PEP3101 no se ha modificado en más de dos años y medio (viernes, 30 de septiembre de 2011).

Actualizar

PEP461 Se acepta agregar% de formato a bytes y bytearray y debe ser parte de Python 3.5 o 3.6. Es otra señal de que el operador% está vivo y coleando.

Marwan Alsabbagh
fuente