
Python tiene 3 formas de formatear cadenas, y una de ellas es mejor que las otras. Pero no nos adelantemos: ¿de qué tipo de formato estamos hablando? Cada vez que queremos saludar a un usuario por su nombre, necesitamos insertar una cadena con un nombre en la cadena de la plantilla. Las entradas de registro más útiles también contienen valores variables. Y aquí hay un ejemplo:
integer = 42 string = 'FORTY_TWO' print('string number %s, or simply %d' % (string, integer)) print('string number {}, or simply {}'.format(string, integer)) print(f'string number {string}, or simply {integer}')
El primer método, formatear con el operador%, vino en Python desde C: imita la función printf. Este método fue el primero en Python, y sigue siendo el único (discutido en el artículo) en Python versión 2.5 y siguientes.
La segunda forma es el método str.format, que pertenece a la clase de cadena incorporada. Llegó con Python 3.0 y fue portado a la versión 2.6. Se ha
recomendado que este método tenga una sintaxis más rica.
El tercer método, f-string, apareció en Python versión 3.6. Como se explica en
PEP-0498 , la creación de una nueva forma de formatear cadenas fue motivada por las deficiencias de los métodos existentes, que los autores caracterizan como propensos a errores, no lo suficientemente flexibles y no elegantes:
Este PEP está impulsado por el deseo de tener una forma más simple de formatear cadenas en Python. Las formas existentes de formateo son propensas a errores, inflexibles o engorrosas.
Entonces, tenemos tres formas de resolver un problema. ¿Pero tal vez esto es una cuestión de gusto y preferencia personal? Quizás, pero el estilo de su código (especialmente el código en un proyecto con una gran cantidad de participantes) definitivamente se beneficiará de la uniformidad. En el mejor de los casos, debe usar un método para formatear cadenas, luego será más fácil leer el código. ¿Pero qué método elegir? ¿Y hay una diferencia en el rendimiento del código?
Intentemos responder la pregunta sobre el rendimiento experimentalmente:
import timeit setup = """ integer = 42 string = 'FORTY_TWO' """.strip() percent_stmt ="'Number %s or simply %d' % (string, integer)" call_stmt = "'Number {} or simply {}'.format(string, integer)" fstr_stmt = """f'Number {string} or simply {integer}'""" def time(stmt): return f"{timeit.timeit(stmt, setup, number=int(1e7)):.3f}" print(f"Timing percent formating: | {time(percent_stmt)}") print(f"Timing call formating: | {time(call_stmt)}") print(f"Timing f-string formating: | {time(fstr_stmt)}")
Resultados en MacBook con Python 3.7:
Timing percent formating: | 2.025 Timing call formating: | 2.943 Timing f-string formating: | 1.348
La diferencia es significativa. Entonces, ¿ejecuta la búsqueda de expresiones regulares en ".format" y reescribe cientos de expresiones? En principio, la tarea es simple pero lleva mucho tiempo. ¡Además de la posibilidad de cometer un error y poner un error en el código que funcionaba anteriormente! Parece que hay espacio para la automatización. De hecho, hay bibliotecas que pueden convertir la mayoría de las expresiones en cadenas f:
flynt ,
pyupgrade .
Flynt es fácil de usar. Por ejemplo, ejecute la conversión en el código fuente del matraz:
38f9d3a65222:~ ikkamens$ git clone https://github.com/pallets/flask.git Cloning into 'flask'... ... Resolving deltas: 100% (12203/12203), done. 38f9d3a65222:~ ikkamens$ flynt flask Flynt run has finished. Stats: Execution time: 0.623s Files modified: 18 Expressions transformed: 43 Character count reduction: 241 (0.04%) _-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_. Please run your tests before commiting. Report bugs as github issues at: https://github.com/ikamensh/flynt Thank you for using flynt! Fstringify more projects and recommend it to your colleagues! _-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_. 38f9d3a65222:~ ikkamens$
También vale la pena señalar la posibilidad de convertir expresiones que ocupan varias líneas y recopilar estadísticas sobre los cambios realizados. La bandera --line_length XX define el límite de longitud de línea después de la conversión. Flynt le permite llamar a pyupgrade con la bandera --upgrade.
Pyupgrade incluye más funciones y puede limpiar su código de muchos artefactos de Python 2, como heredar de objetos, especificar nombres de clases en super y
mucho más . Pyupgrade está diseñado para usarse con
pre-commit , una utilidad para modificar automáticamente el código antes de los commits.
Es mejor convertir la fuente en un gita u otro control de versión. Vale la pena ejecutar pruebas y observar los cambios usted mismo (usando entornos git diff o PyCharm). Mientras vivamos entre aquellos a quienes les importa, que el código se haya convertido en un par de caracteres más cortos, la conversión proactiva también les ahorrará tiempo. Después de todo, tarde o temprano alguien comenzará a hacer con sus manos lo que puede convertirse en una utilidad. Las cadenas F solo funcionan en Python 3.6+, pero pronto esto no será un problema ya que
otras versiones se volverán obsoletas .
Vale la pena señalar que el método clásico .format no funcionará por completo. En el caso de que use la misma plantilla para crear mensajes con diferentes variables en diferentes lugares del código, debe guardar esta plantilla en una variable y usarla; el principio "No se repita" es mucho más importante que ganar nanosegundos al formatear una cadena.
Conclusiones:
Analizamos los tres métodos de formateo de cadenas disponibles en Python 3.6+, su breve historial y comparamos su rendimiento. También examinamos las herramientas de código abierto para convertir automáticamente el código a un nuevo método para formatear cadenas y sus funciones adicionales. ¡No olvide las cosas simples en su código, y buena suerte!