Formato de cadena de Python () con dict con claves enteras

Me gustaría usar el format() de cadena de Python format() para actuar como una plantilla rápida y sucia. Sin embargo, el dict que me gustaría usar tiene claves que son (representaciones de cadena) de enteros. Un ejemplo simplificado sigue:

 s = 'hello there {5}' d = {'5': 'you'} s.format(**d) 

El código anterior arroja el siguiente error:

 Traceback (most recent call last): File "", line 1, in  IndexError: tuple index out of range 

¿Es posible hacer lo anterior?

Hemos establecido que no funcionará, pero ¿qué tal una solución?

Aunque str.format no funcionará en este caso, curiosamente el antiguo formato de % . Esto no es recomendable, pero solicitó una plantilla rápida y sucia .

 >>> 'hello there %(5)s' % {'5': 'you'} 'hello there you' 

Tenga en cuenta, sin embargo, que esto no funcionará para las teclas enteras.

 >>> 'hello there %(5)s' % {5: 'you'} Traceback (most recent call last): File "", line 1, in  'hello there %(5)s' % {5: 'you'} KeyError: '5' 

Me encanta la idea de extender el Formatter para que permita nombres de campo arbitrarios (enteros, nombres de campo con dos puntos, etc.). Una implementación podría verse así:

 import string, re class QuFormatter(string.Formatter): def _quote(self, m): if not hasattr(self, 'quoted'): self.quoted = {} key = '__q__' + str(len(self.quoted)) self.quoted[key] = m.group(2) return '{' + m.group(1) + key + m.group(3) + '}' def parse(self, format_string): return string.Formatter.parse(self, re.sub(r'{([^}`]*)`([^}`]*)`([^}]*)}', self._quote, format_string)) def get_value(self, key, args, kwargs): if key.startswith('__q__'): key = self.quoted[key] return string.Formatter.get_value(self, key, args, kwargs) 

Uso:

 d = {'5': 'you', '6': 'me', "okay":1, "weird:thing!": 123456} print QuFormatter().format( 'hello there {`5`} {`6`:20s}--{okay}--{`weird:thing!`:20,d}', **d) 

Así que los campos en backticks son tratados literalmente.

Vea esta publicación para respuestas a sus problemas. Parece que no puede usar cadenas compuestas de números como claves de diccionario en cadenas de formato ( enlace docs ).

Si puede usar una clave distinta de 5, entonces funcionará:

 my_string='hello there {spam:s}' d={'spam': 'you'} print my_string.format(**d) # Returns "hello there you" 

Desde PEP 3101

La clase de cadena incorporada (y también la clase Unicode en 2.6) ganará un nuevo método, ‘formato’, que toma un número arbitrario de argumentos posicionales y de palabras clave:

 "The story of {0}, {1}, and {c}".format(a, b, c=d) 

Dentro de una cadena de formato, cada argumento posicional se identifica con un número, comenzando desde cero, por lo que en el ejemplo anterior, ‘a’ es el argumento 0 y ‘b’ es el argumento 1. Cada argumento de palabra clave se identifica por su nombre de palabra clave, por lo que en El ejemplo anterior, ‘c’ se usa para referirse al tercer argumento.

Los valores numéricos utilizados en str.format son argumentos posicionales. Así que no puedes hacer eso.

Puede llegar a PEP 3101 desde aquí . La sección relacionada está bajo los métodos de cadena.

Como se mencionó @Volatility, puede usar % formatter para esto.

Podría hacer algo con get_value en una string.Formatter personalizada. string.Formatter para probar los campos de reemplazo como claves del diccionario antes de volver al índice en las claves arg: tenga en cuenta el posible conflicto de prioridad e intención aquí … así que no se recomienda exactamente, pero sí una idea de lo que es posible:

 import string class MyFormatter(string.Formatter): def get_value(self, key, args, kwargs): try: return kwargs[str(key)] except KeyError: return super(MyFormatter, self).get_value(key, args, kwargs) s = 'hello there {5} - you are number {0}' d = {'5': 'you'} print MyFormatter().format(s, 1, 2, 3, **d) # hello there you - you are number 1 

En realidad es posible, usando el hecho de que {k} busca el (k+1) th argumento posicional.

 def populate_list(d): """ Return a list l verifying l[k] = d[str(k)] for each natural k """ return [d.get(str(k)) for k in range(1 + max(map(int, d)))] if d else [] def format_with_int_keys(s,d): """ Replace each {k} in s by d[str(k)] """ return s.format(*populate_list(d)) s = 'hello there {5}' d = {'5': 'you'} print (format_with_int_keys(s,d)) 

Edición : en realidad es una versión detallada de la solución @wim.