Formato de cadena de Python: Cuándo usar el indicador de conversión! S

¿Cuál es la diferencia entre estas dos declaraciones de formato de cadena en Python:

'{0}'.format(a) '{0!s}'.format(a) 

Ambos tienen la misma salida si a es un número entero, una lista o un diccionario. ¿El primero {0} haciendo una llamada implícita a str() ?

Fuente

PD: palabras clave: exclamación / bang “! S” formateando

Se menciona en la documentación:

El campo de conversión provoca una coacción de tipo antes de formatear. Normalmente, el trabajo de formatear un valor se realiza mediante el __format__() del propio valor. Sin embargo, en algunos casos es conveniente forzar el formato de un tipo como una cadena, anulando su propia definición de formato. Al convertir el valor en una cadena antes de llamar __format__() , se omite la lógica de formato normal.

Actualmente se admiten dos indicadores de conversión: ‘ !s ‘ que llama a str() en el valor, y ‘ !r ‘ que llama a repr() .

Se puede tomar un ejemplo (nuevamente de la documentación ) para mostrar la diferencia:

 >>> "repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2') "repr() shows quotes: 'test1'; str() doesn't: test2" 

Dicho simplemente:

  • '{0}'.format(a) usará el resultado de a.__format__() para mostrar el valor
  • '{0!s}'.format(a) usará el resultado de a.__str__() para mostrar el valor
  • '{0!r}'.format(a) usará el resultado de a.__repr__() para mostrar el valor

 >>> class C: ... def __str__(self): return "str" ... def __repr__(self): return "repr" ... def __format__(self, format_spec): return "format as " + str(type(format_spec)) ... >>> c = C() >>> print "{0}".format(c) format as  >>> print u"{0}".format(c) format as  >>> print "{0!s}".format(c) str >>> print "{0!r}".format(c) repr 

Con respecto al segundo argumento de __format__ , para citar PEP 3101 “Controlar el formateo en una base por tipo” :

El argumento ‘format_spec’ será un objeto de cadena o un objeto Unicode, dependiendo del tipo de cadena de formato original. El método __format__ debe probar el tipo de parámetro de los especificadores para determinar si se debe devolver una cadena o un objeto Unicode. Es responsabilidad del método __format__ devolver un objeto del tipo adecuado.

Gracias al comentario y la respuesta de @ hjpotter92 por la explicación:

Aquí hay un ejemplo que muestra la diferencia (es cuando reemplaza el método __format__ )

 class MyClass: i = 12345 def __format__(self, i): return 'I Override' >>> obj = MyClass() >>> '{0}'.format(obj) 'I Override' >>> '{0!s}'.format(obj) '<__main__.MyClass instance at 0x021AA6C0>'