Pregunta Formateo de cadena de Python:% vs. format


Python 2.6 introdujo el str.format() método con una sintaxis ligeramente diferente de la existente % operador. ¿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 ocurre el formateo de cadenas en Python? Por ejemplo, si mi nivel de registro está configurado en ALTO, todavía recibiré un golpe por realizar lo siguiente % ¿operación? Y si es así, ¿hay alguna forma de evitar esto?

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

1178
2018-02-22 18:46


origen


Respuestas:


Para responder a tu primera pregunta ... .format simplemente parece más sofisticado en muchos sentidos. Una cosa molesta sobre % es también cómo puede tomar una variable o una tupla. Creerías que lo siguiente siempre funcionaría:

"hi there %s" % name

aún, si name pasa a ser (1, 2, 3), arrojará un TypeError. Para garantizar que siempre se imprima, tendrías que hacer

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

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

¿Por qué no lo usarías?

  • sin 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 del formato de cadena. Y Python, al no ser un lenguaje perezoso, evalúa las expresiones antes de llamar a las funciones, por lo que en su log.debug ejemplo, la expresión "some debug info: %s"%some_infoprimero evaluará, p. "some debug info: roflcopters are active", entonces esa cadena se pasará a log.debug().


852
2018-02-22 18:49



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, puede usarse como 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

281
2018-06-13 20:20



Asumiendo que estás usando Python logging módulo, puede pasar los argumentos de formato de cadena como argumentos al .debug() método en lugar de hacer el formateo usted mismo:

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

lo que evita hacer el formateo a menos que el registrador realmente registre algo.


124
2018-02-22 19:21



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

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

Nota la f" prefijo. Si prueba esto en Python 3.5 o anterior, obtendrá un SyntaxError.

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


88
2018-04-15 11:12



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


54
2017-08-01 03:01



Pero ten cuidado, ahora descubrí un problema al intentar reemplazar todo % con .format en el código existente: '{}'.format(unicode_string) intentará codificar unicode_string y probablemente fallará.

Solo mira este registro de la sesión interactiva 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 a % operador producirá una cadena Unicode incluso si la cadena original no fue 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 el .format la función aumentará "UnicodeEncodeError":

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

y funcionará con un argumento Unicode correcto solo si la cadena original fue Unicode.

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

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


51
2017-09-03 18:15



Sin embargo, otra ventaja de .format (que no veo en las respuestas): puede tomar las propiedades del objeto.

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 un 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 yo puedo decir.


33
2017-12-04 18:33



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

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.00000000000000000000000312375239000000009907464850   0.00000000000000000000000312375239000000000000000000

Seguramente podría haber soluciones alternativas, pero aún podría considerar usar el format() método de inmediato.


27
2018-05-13 17:10



% 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 @Chris Cogdon por el código de muestra.


20
2018-06-13 18:43