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?
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!"
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_info
primero 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