16 Pregunta: Formato de cadena:% vs. .format

pregunta creada en Wed, May 29, 2019 12:00 AM

Python 2.6 introdujo el método str.format() con una forma ligeramente diferente sintaxis del operador % existente. ¿Cuál es mejor y para qué situaciones?

  1. Lo siguiente usa cada método y tiene el mismo resultado, entonces, ¿cuál es la diferencia?

     
    #!/usr/bin/python
    sub1 = "python string!"
    sub2 = "an arg"
    
    a = "i am a %s" % sub1
    b = "i am a {0}".format(sub1)
    
    c = "with %(kwarg)s!" % {'kwarg':sub2}
    d = "with {kwarg}!".format(kwarg=sub2)
    
    print a    # "i am a python string!"
    print b    # "i am a python string!"
    print c    # "with an arg!"
    print d    # "with an arg!"
    
  2. Además, ¿cuándo se produce el formato de cadena en Python? Por ejemplo, si mi nivel de registro se establece en ALTO, ¿seguiré teniendo un impacto para realizar la siguiente operación %? Y si es así, ¿hay alguna manera de evitar esto?

     
    log.debug("some debug info: %s" % some_info)
    
1279
  1. 2011-02-22 18: 50: 34Z
  2. Para principiantes: Aquí hay un muy buen tutorial que enseña ambos estilos. Personalmente uso el estilo % más antiguo con más frecuencia, porque si no necesita las capacidades mejoradas del estilo format(), el estilo % suele ser mucho más conveniente.
    2016-04-12 09: 24: 45Z
  3. 2016-04-12 09: 26: 42Z
  4. 2017-01-06 09: 39: 25Z
  5. Para responder su segunda pregunta, desde 3.2 puede usar el formato {} si usa un formateador personalizado (vea docs.python.org/3/library/logging.html#logging.Formatter )
    2017-09-20 21: 36: 52Z
16 Respuestas                              16                         

Para responder tu primera pregunta ... .format parece más sofisticado de muchas maneras. Algo molesto de % también es cómo puede tomar una variable o una tupla. Usted pensaría que lo siguiente siempre funcionaría:

 
"hi there %s" % name

aún, si name resulta ser (1, 2, 3), lanzará un TypeError. Para garantizar que siempre se imprima, deberías hacerlo

 
"hi there %s" % (name,)   # supply the single argument as a single-item tuple

que es simplemente feo. .format no tiene esos problemas. También en el segundo ejemplo que dio, el ejemplo .format tiene un aspecto mucho más limpio.

¿Por qué no lo usarías?

  • no saberlo (yo antes de leer esto)
  • tener que ser compatible con Python 2.5

Para responder a su segunda pregunta, el formato de cadena ocurre al mismo tiempo que cualquier otra operación, cuando se evalúa la expresión de formato de cadena. Y Python, al no ser un lenguaje vago, evalúa las expresiones antes de llamar a las funciones, por lo que en su ejemplo log.debug, la expresión "some debug info: %s"%some_info primero se evaluará, por ejemplo. "some debug info: roflcopters are active", entonces esa cadena pasará a log.debug().

    
914
2015-05-01 12: 12: 38Z
  1. What about "%(a)s, %(a)s" % {'a':'test'}
    2012-08-23 09: 53: 17Z
  2. Tenga en cuenta que perderá tiempo en log.debug("something: %s" % x) pero no en log.debug("something: %s", x) El formato de cadena se manejará en el método y no obtendrá el impacto de rendimiento si no se registra. Como siempre, Python anticipa sus necesidades =)
    2012-12-14 23: 13: 47Z
  3. ted: es un truco de peor aspecto que hacer lo mismo que '{0}, {0}'.format('test').
    2013-01-30 20: 43: 48Z
  4. El punto es: el único argumento recurrente de que la nueva sintaxis permite reordenar los elementos es un punto discutible: puede hacer lo mismo con la sintaxis antigua. ¡La mayoría de las personas no saben que esto ya está definido en Ansi C99 Std! Consulte una copia reciente de man sprintf y conozca la notación $ dentro de % marcadores de posición
    2013-02-20 12: 42: 29Z
  5. @ cfi: Si quiere decir algo así como printf("%2$d", 1, 3) para imprimir "3", eso está especificado en POSIX, no en C99. La misma página de manual a la que hizo referencia en las notas, "El estándar C99 no incluye el estilo usando '$' ...".
    2013-03-07 23: 55: 22Z

Algo que el operador de módulo (%) no puede hacer, afaik:

 
tu = (12,45,22222,103,6)
print '{0} {2} {1} {2} {3} {2} {4} {2}'.format(*tu)

resultado

 
12 22222 45 22222 103 22222 6 22222

Muy útil.

Otro punto: format(), al ser una función, se puede usar como un argumento en otras funciones:

 
li = [12,45,78,784,2,69,1254,4785,984]
print map('the number is {}'.format,li)   

print

from datetime import datetime,timedelta

once_upon_a_time = datetime(2010, 7, 1, 12, 0, 0)
delta = timedelta(days=13, hours=8,  minutes=20)

gen =(once_upon_a_time +x*delta for x in xrange(20))

print '\n'.join(map('{:%Y-%m-%d %H:%M:%S}'.format, gen))

Resultados en:

 
['the number is 12', 'the number is 45', 'the number is 78', 'the number is 784', 'the number is 2', 'the number is 69', 'the number is 1254', 'the number is 4785', 'the number is 984']

2010-07-01 12:00:00
2010-07-14 20:20:00
2010-07-28 04:40:00
2010-08-10 13:00:00
2010-08-23 21:20:00
2010-09-06 05:40:00
2010-09-19 14:00:00
2010-10-02 22:20:00
2010-10-16 06:40:00
2010-10-29 15:00:00
2010-11-11 23:20:00
2010-11-25 07:40:00
2010-12-08 16:00:00
2010-12-22 00:20:00
2011-01-04 08:40:00
2011-01-17 17:00:00
2011-01-31 01:20:00
2011-02-13 09:40:00
2011-02-26 18:00:00
2011-03-12 02:20:00
    
296
2015-01-14 19: 24: 14Z
  1. Puede usar el formato de estilo antiguo en map tan fácilmente como el formato. map('some_format_string_%s'.__mod__, some_iterable)
    2012-11-28 05: 49: 49Z
  2. @ cfi: demuestre que tiene razón al reescribir el ejemplo anterior en C99
    2014-02-15 14: 11: 21Z
  3. @ MarcH: printf("%2$s %1$s\n", "One", "Two"); compilado con gcc -std=c99 test.c -o test, la salida es Two One. Pero me quedo corregido: En realidad es una extensión POSIX y no C. No puedo encontrarla nuevamente en el estándar C /C ++ , donde pensé que lo había visto. El código funciona incluso con la bandera estándar 'c90'. página del manual sprintf . Esto no lo enumera, pero permite a las bibliotecas implementar un superconjunto. Mi argumento original sigue siendo válido, reemplazando C con Posix
    2014-02-15 15: 18: 13Z
  4. Mi primer comentario aquí, no se aplica a esta respuesta. Me arrepiento de las frases. En Python no podemos usar el operador de módulo % para reordenar los marcadores de posición. Todavía me gustaría no borrar ese primer comentario por coherencia de comentarios aquí. Pido disculpas por haber desahogado mi ira aquí. Está dirigido contra la afirmación a menudo hecha de que la antigua sintaxis per se no permitiría esto. En lugar de crear una sintaxis completamente nueva, podríamos haber introducido las extensiones std Posix. Podríamos tener ambos.
    2014-02-15 15: 25: 44Z
  5. 'modulo' se refiere al operador que evalúa el resto después de una división. en este caso, el signo de porcentaje no es un operador de módulo.
    2014-05-08 21: 09: 26Z

Suponiendo que esté utilizando el módulo logging de Python, puede pasar los argumentos de formato de cadena como argumentos al método .debug() en lugar de hacerlo usted mismo:

 
log.debug("some debug info: %s", some_info)

que evita realizar el formateo a menos que el registrador realmente registre algo.

    
138
2015-01-14 19: 28: 08Z
  1. Esta es una información útil que acabo de aprender. Es una pena que no tenga su propia pregunta, ya que parece estar separada de la pregunta principal. Lástima que el OP no dividió su pregunta en dos preguntas separadas.
    2012-11-14 07: 36: 22Z
  2. Puedes usar el formato de dict como este: log.debug("some debug info: %(this)s and %(that)s", dict(this='Tom', that='Jerry')) Sin embargo, no puedes usar la nueva sintaxis del estilo .format() aquí, ni siquiera en Python 3.3, que es una vergüenza.
    2012-11-25 17: 00: 11Z
  3. 2013-01-30 19: 56: 05Z
  4. El beneficio principal de esto no es el rendimiento (la interpolación de la cadena será rápida en comparación con lo que esté haciendo con la salida del registro, por ejemplo, la visualización en un terminal, guardando en el disco) Es que si tiene un agregador de registro, puede indicarle "tiene 12 instancias de este mensaje de error", incluso si todos tienen valores 'some_info' diferentes. Si el formato de la cadena se realiza antes de pasar la cadena a log.debug, esto es imposible. El agregador solo puede decir "tienes 12 mensajes de registro diferentes"
    2013-10-10 08: 04: 25Z
  5. Si le preocupa el rendimiento, use la sintaxis literal dict {} en lugar de una instanciación de la clase dict (): doughellmann.com/2012/11/…
    2014-02-14 11: 03: 14Z

A partir de Python 3.6 (2016) puede usar f -cintas para sustituir variables:

 
>>> origin = "London"
>>> destination = "Paris"
>>> f"from {origin} to {destination}"
'from London to Paris'

Note el prefijo f". Si lo intentas en Python 3.5 o anterior, obtendrás un SyntaxError.

Consulte https://docs.python.org/3.6/reference /lexical_analysis.html#f-strings

    
108
2018-03-13 16: 52: 45Z
  1. Esto no responde la pregunta. Otra respuesta que menciona f-strings al menos habla sobre el rendimiento: stackoverflow.com/a/51167833/7851470
    2019-06-17 12: 00: 02Z

PEP 3101 propone el reemplazo del operador % con el nuevo, Formato de cadena avanzado en Python 3, donde sería el predeterminado.

    
57
2017-02-13 15: 51: 53Z
  1. Falso: "La compatibilidad hacia atrás se puede mantener al dejar los mecanismos existentes en su lugar."; por supuesto, .format no reemplazará el formato de cadena %.
    2013-01-28 23: 32: 43Z
  2. No, la postulación de BrainStorms es verdadera: "pretende reemplazar el '%' existente". La cita de Tobias significa que ambos sistemas coexistirán por algún tiempo. RTFPEP
    2015-08-19 15: 00: 43Z

Pero tenga cuidado, ahora mismo he descubierto un problema al intentar reemplazar el % con .format en el código existente: El '{}'.format(unicode_string) intentará codificar unicode_string y probablemente fallará.

Solo mire este registro de sesión interactivo de Python:

 
Python 2.7.2 (default, Aug 27 2012, 19:52:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
; s='й'
; u=u'й'
; s
'\xd0\xb9'
; u
u'\u0439'

s es solo una cadena (llamada 'matriz de bytes' en Python3) y u es una cadena Unicode (llamada 'cadena' en Python3):

 
; '%s' % s
'\xd0\xb9'
; '%s' % u
u'\u0439'

Cuando le das un objeto Unicode como parámetro al operador %, producirá una cadena Unicode incluso si la cadena original no era Unicode:

 
; '{}'.format(s)
'\xd0\xb9'
; '{}'.format(u)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0439' in position 0: ordinal not in range(256)

pero la función .format generará "UnicodeEncodeError":

 
; u'{}'.format(s)
u'\xd0\xb9'
; u'{}'.format(u)
u'\u0439'

y funcionará con un argumento Unicode bien solo si la cadena original era Unicode.

 
; '{}'.format(u'i')
'i'

o si la cadena de argumento se puede convertir en una cadena (llamada 'matriz de bytes')

    
52
2015-01-14 19: 27: 33Z
  1. Simplemente no hay razón para cambiar el código de trabajo a menos que las características adicionales del nuevo método format sean realmente necesarias ...
    2013-01-28 22: 51: 44Z
  2. está totalmente de acuerdo contigo, Tobias, pero a veces es necesario al actualizar a versiones más nuevas de Python
    2013-01-30 13: 17: 08Z
  3. Por ejemplo? AFAIK, nunca ha sido necesario; No creo que sea probable que la interpolación de la cadena % desaparezca alguna vez.
    2013-01-31 13: 45: 02Z
  4. Considero que la función .format () es más segura que% para las cadenas. A menudo veo errores de principiantes como este "p1=%s p2=%d" % "abc", 2 o "p1=%s p2=%s" % (tuple_p1_p2,). Puede que piense que es culpa del codificador, pero creo que es solo una sintaxis extraña y defectuosa que se ve bien para el script rápido pero es mala para el código de producción.
    2014-01-06 15: 07: 03Z
  5. Pero no me gusta la sintaxis de .format (), estaría más feliz con los viejos %s, %02d como "p1=%s p2=%02d".format("abc", 2). Culpo a los que inventaron y aprobaron el formato de llaves que necesita que usted se escape de ellos como {{}} y se vea feo.
    2014-01-06 15: 15: 04Z

Otra ventaja más de .format (que no veo en las respuestas): puede tomar propiedades de objetos.

 
In [12]: class A(object):
   ....:     def __init__(self, x, y):
   ....:         self.x = x
   ....:         self.y = y
   ....:         

In [13]: a = A(2,3)

In [14]: 'x is {0.x}, y is {0.y}'.format(a)
Out[14]: 'x is 2, y is 3'

O, como argumento de palabra clave:

 
In [15]: 'x is {a.x}, y is {a.y}'.format(a=a)
Out[15]: 'x is 2, y is 3'

Esto no es posible con % por lo que puedo decir.

    
34
2015-06-19 16: 42: 39Z
  1. Esto parece más ilegible de lo necesario en comparación con el 'x is {0}, y is {1}'.format(a.x, a.y) equivalente. Solo debe utilizarse cuando la operación a.x es muy costosa.
    2015-03-29 14: 03: 21Z
  2. @ dtheodor Con un tweak para usar un argumento de palabra clave en lugar de un argumento posicional ... 'x is {a.x}, y is {a.y}'.format(a=a). Más legible que ambos ejemplos.
    2015-04-17 21: 11: 54Z
  3. @ CivFan O, si tiene más de un objeto, 'x is {a.x}, y is {a.y}'.format(**vars())
    2015-06-18 17: 02: 03Z
  4. También tenga en cuenta este de la misma manera: '{foo[bar]}'.format(foo={'bar': 'baz'}).
    2016-07-23 22: 01: 44Z
  5. Esto es increíblemente útil para aplicaciones orientadas al cliente, donde su aplicación proporciona un conjunto estándar de opciones de formato con una cadena de formato suministrada por el usuario. Uso esto todo el tiempo. El archivo de configuración, por ejemplo, tendrá alguna propiedad "messagestring", que el usuario puede proporcionar wI Your order, number {order[number]} was processed at {now:%Y-%m-%d %H:%M:%S}, will be ready at about {order[eta]:%H:%M:%S} o lo que quieran. Esto es mucho más limpio que intentar ofrecer la misma funcionalidad con el formateador anterior. Hace que las cadenas de formato proporcionadas por el usuario sean mucho más potentes.
    2016-09-30 21: 33: 04Z

Como descubrí hoy, la antigua forma de formatear cadenas a través de % no es compatible con Decimal, el módulo de Python para aritmética de punto fijo decimal y punto flotante, listo para usar.

Ejemplo (usando Python 3.3.5):

 
#!/usr/bin/env python3

from decimal import *

getcontext().prec = 50
d = Decimal('3.12375239e-24') # no magic number, I rather produced it by banging my head on my keyboard

print('%.50f' % d)
print('{0:.50f}'.format(d))

Salida:

  

0.000000000000000000003000312375239000000009907464850   0.00000000000000000000000312375239000000000000000000

Es probable que existan soluciones alternativas, pero aún puede considerar el uso del método format() de inmediato.

    
30
2015-01-14 19: 24: 41Z
  1. Eso probablemente se deba a que el formato de nuevo estilo llama al str(d) antes de expandir el parámetro, mientras que el formato de estilo antiguo probablemente llame al float(d) primero.
    2014-10-21 19: 53: 26Z
  2. Pensaría que sí, pero str(d) devuelve "3.12375239e-24", no "0.00000000000000000000000312375239000000000000000000"
    2015-06-18 16: 52: 56Z

% da un mejor rendimiento que format de mi prueba.

Código de prueba:

Python 2.7.2:

 
import timeit
print 'format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')")
print '%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')")

Resultado:

 
> format: 0.470329046249
> %: 0.357107877731

Python 3.5.2

 
import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))

Resultado

 
> format: 0.5864730989560485
> %: 0.013593495357781649

Se ve en Python2, la diferencia es pequeña, mientras que en Python3, % es mucho más rápido que format.

Gracias a @Chris Cogdon por el código de muestra.

    
27
2017-10-26 18: 11: 52Z
  1. En su lugar, str.format ofrece más funcionalidades (especialmente el formato de tipo especializado, por ejemplo, '{0:%Y-%m-%d}'.format(datetime.datetime.utcnow())). El rendimiento no puede ser el requisito absoluto de todos los trabajos. Utilice la herramienta adecuada para el trabajo.
    2011-09-18 17: 25: 08Z
  2. "La optimización prematura es la raíz de todo mal" o al menos Donald Knuth dijo una vez ...
    2012-10-17 13: 07: 56Z
  3. Mantener un esquema de formato conocido (siempre que se ajuste a las necesidades, como lo hace en la gran mayoría de los casos), y que es el doble de rápido, No es una "optimización prematura" sino simplemente razonable. Por cierto, el operador % permite reutilizar el conocimiento printf; La interpolación de diccionarios es una extensión muy simple del principio.
    2013-01-28 23: 03: 00Z
  4. En realidad, he experimentado lo contrario en una situación. El formato de nuevo estilo fue más rápido. ¿Puede proporcionar el código de prueba que utilizó?
    2014-10-21 19: 54: 34Z
  5. Parece una publicación seriamente desperdiciada sin ningún ejemplo o razonamiento, solo reclamaciones.
    2016-05-29 02: 40: 09Z

Como nota al margen, no tiene que dar un golpe de rendimiento para usar un nuevo formato de estilo con el registro. Puede pasar cualquier objeto a logging.debug, logging.info, etc. que implemente el método mágico __str__. Cuando el módulo de registro ha decidido que debe emitir su objeto de mensaje (sea el que sea), llama al str(message_object) antes de hacerlo. Así que podrías hacer algo como esto:

 
import logging


class NewStyleLogMessage(object):
    def __init__(self, message, *args, **kwargs):
        self.message = message
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        args = (i() if callable(i) else i for i in self.args)
        kwargs = dict((k, v() if callable(v) else v) for k, v in self.kwargs.items())

        return self.message.format(*args, **kwargs)

N = NewStyleLogMessage

# Neither one of these messages are formatted (or calculated) until they're
# needed

# Emits "Lazily formatted log entry: 123 foo" in log
logging.debug(N('Lazily formatted log entry: {0} {keyword}', 123, keyword='foo'))


def expensive_func():
    # Do something that takes a long time...
    return 'foo'

# Emits "Expensive log entry: foo" in log
logging.debug(N('Expensive log entry: {keyword}', keyword=expensive_func))

Todo esto se describe en la documentación de Python 3 ( https: //docs.python.org/3/howto/logging-cookbook.html#formatting-styles ). Sin embargo, también funcionará con Python 2.6 ( https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages ).

Una de las ventajas de usar esta técnica, aparte del hecho de que es un agnóstico de estilo de formato, es que permite valores perezosos, por ejemplo. la función expensive_func anterior. Esto proporciona una alternativa más elegante a los consejos que se dan en los documentos de Python aquí: https: //docs.python.org/2.6/library/logging.html#optimization .

    
14
2014-10-21 19: 55: 49Z
  1. Me gustaría poder promocionar esto más. Permite el registro con format sin el impacto de rendimiento; lo hace anulando __str__ precisamente como logging fue diseñado para: acorta la llamada de función a una sola letra (N) que se siente muy similar a algunas de las formas estándar para definir cadenas: Y permite la llamada de función perezosa. ¡Gracias! +1
    2015-01-26 22: 21: 52Z
  2. ¿Este resultado es diferente al usar el parámetro logging.Formatter(style='{')?
    2017-05-10 02: 03: 05Z

Si tu python > = 3.6, el literal formateado con F-string es tu nuevo amigo.

Es más simple, limpio y con mejor rendimiento.

 
In [1]: params=['Hello', 'adam', 42]

In [2]: %timeit "%s %s, the answer to everything is %d."%(params[0],params[1],params[2])
448 ns ± 1.48 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [3]: %timeit "{} {}, the answer to everything is {}.".format(*params)
449 ns ± 1.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [4]: %timeit f"{params[0]} {params[1]}, the answer to everything is {params[2]}."
12.7 ns ± 0.0129 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
    
12
2018-08-25 01: 05: 27Z

Una situación en la que % puede ayudar es cuando está formateando expresiones de expresiones regulares. Por ejemplo,

 
'{type_names} [a-z]{2}'.format(type_names='triangle|square')

plantea IndexError. En esta situación, puede utilizar:

 
'%(type_names)s [a-z]{2}' % {'type_names': 'triangle|square'}

Esto evita escribir la expresión regular como '{type_names} [a-z]{{2}}'. Esto puede ser útil cuando tiene dos expresiones regulares, donde una se usa sola sin formato, pero la concatenación de ambas está formateada.

    
9
2015-04-09 20: 41: 40Z
  1. O simplemente use '{type_names} [a-z]{{2}}'.format(type_names='triangle|square'). Es como decir que .format() puede ayudar cuando se usan cadenas que ya contienen un carácter de porcentaje. Por supuesto. Tienes que escapar de ellos entonces.
    2017-03-02 16: 24: 40Z
  2. @ Alfe Tiene razón, y es por eso que la respuesta comienza con "One situation where % may help is when you are formatting regex expressions." Específicamente, suponga que a=r"[a-z]{2}" es un fragmento de expresiones regulares que se usará en dos expresiones finales diferentes (por ejemplo, c1 = b + a y c2 = a). Suponga que c1 debe ser format ed (por ejemplo, b debe tener un formato de tiempo de ejecución), pero c2 no. Entonces necesitas a=r"[a-z]{2}" para c2 y a=r"[a-z]{{2}}" para c1.format(...).
    2017-03-02 16: 41: 41Z

Yo agregaría que desde la versión 3.6, podemos usar cadenas como las siguientes

 
foo = "john"
bar = "smith"
print(f"My name is {foo} {bar}")

Que das

  

Mi nombre es John Smith

Todo se convierte en cadenas

 
mylist = ["foo", "bar"]
print(f"mylist = {mylist}")

Resultado:

  

mylist = ['foo', 'bar']

puedes pasar la función, como en el método de otros formatos

 
print(f'Hello, here is the date : {time.strftime("%d/%m/%Y")}')

Dando por ejemplo

  

Hola, aquí está la fecha: 16/04/2018

    
5
2018-04-16 14: 51: 11Z

Para la versión de Python > = 3.6 (vea PEP 498 )

 
s1='albha'
s2='beta'

f'{s1}{s2:>10}'

#output
'albha      beta'
    
2
2018-03-15 16: 52: 14Z

Pero una cosa es que también si tiene llaves de llaves anidadas, no funcionará con el formato pero % funcionará.

Ejemplo:

 
>>> '{{0}, {1}}'.format(1,2)
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    '{{0}, {1}}'.format(1,2)
ValueError: Single '}' encountered in format string
>>> '{%s, %s}'%(1,2)
'{1, 2}'
>>> 
    
1
2018-08-25 01: 08: 57Z
  1. usted podría hacer esto, pero estoy de acuerdo en que es terrible '{{{0}, {1}}}'. format (1, 2)
    2018-11-15 11: 15: 39Z

Comparativa de Python 3.6.7:

 
#!/usr/bin/env python
import timeit

def time_it(fn):
    """
    Measure time of execution of a function
    """
    def wrapper(*args, **kwargs):
        t0 = timeit.default_timer()
        fn(*args, **kwargs)
        t1 = timeit.default_timer()
        print("{0:.10f} seconds".format(t1 - t0))
    return wrapper


@time_it
def new_new_format(s):
    print("new_new_format:", f"{s[0]} {s[1]} {s[2]} {s[3]} {s[4]}")


@time_it
def new_format(s):
    print("new_format:", "{0} {1} {2} {3} {4}".format(*s))


@time_it
def old_format(s):
    print("old_format:", "%s %s %s %s %s" % s)


def main():
    samples = (("uno", "dos", "tres", "cuatro", "cinco"), (1,2,3,4,5), (1.1, 2.1, 3.1, 4.1, 5.1), ("uno", 2, 3.14, "cuatro", 5.5),) 
    for s in samples:
        new_new_format(s)
        new_format(s)
        old_format(s)
        print("-----")


if __name__ == '__main__':
    main()

Salida:

 
new_new_format: uno dos tres cuatro cinco
0.0000170280 seconds
new_format: uno dos tres cuatro cinco
0.0000046750 seconds
old_format: uno dos tres cuatro cinco
0.0000034820 seconds
-----
new_new_format: 1 2 3 4 5
0.0000043980 seconds
new_format: 1 2 3 4 5
0.0000062590 seconds
old_format: 1 2 3 4 5
0.0000041730 seconds
-----
new_new_format: 1.1 2.1 3.1 4.1 5.1
0.0000092650 seconds
new_format: 1.1 2.1 3.1 4.1 5.1
0.0000055340 seconds
old_format: 1.1 2.1 3.1 4.1 5.1
0.0000052130 seconds
-----
new_new_format: uno 2 3.14 cuatro 5.5
0.0000053380 seconds
new_format: uno 2 3.14 cuatro 5.5
0.0000047570 seconds
old_format: uno 2 3.14 cuatro 5.5
0.0000045320 seconds
-----
    
1
2019-02-05 09: 56: 38Z
  1. Debes ejecutar cada ejemplo varias veces, una sola ejecución puede ser engañosa, por ejemplo. El sistema operativo puede estar generalmente ocupado, por lo que la ejecución de su código se retrasa. consulte los documentos: docs.python.org/3/library/timeit.html>. (bonito avatar, Guybrush!)
    2019-02-08 07: 33: 47Z
fuente colocada aquí