2010-08-21 10 views
15

¿Hay alguna manera de utilizar python string.format de modo que no se produzca ninguna excepción cuando falta un índice, en su lugar se inserta una cadena vacía?formato de cadena python suprimir/silencioso keyerror/indexerror

result = "i am an {error} example string {error2}".format(hello=2,error2="success") 

aquí, resultado debe ser:

"i am an example string success" 

En este momento, Python lanza una KeyError y se detiene el formateo. ¿Es posible cambiar este comportamiento?

Gracias

Editar:

Existe Template.safe_substitute (aun que deja el patrón intacta en lugar de insertar una cadena vacía), pero no pudo algo similar para string.format

El el comportamiento deseado sería similar a la sustitución de cadenas en php.

class Formatter(string.Formatter): 
    def get_value(self,key,args,kwargs): 
    try: 
     if hasattr(key,"__mod__"): 
      return args[key] 
     else: 
      return kwargs[key] 
    except: 
     return "" 

Esto parece proporcionar el comportamiento deseado.

+0

También puede usar 'str.format_map()' como se describe en [esta respuesta] (http://stackoverflow.com/a/17215533/877069). –

Respuesta

5

Desafortunadamente, no, no hay ninguna manera de hacerlo por defecto. Sin embargo se puede proporcionarla defaultdict u objeto con __getattr__ anulado, y el uso de la siguiente manera:

class SafeFormat(object): 
    def __init__(self, **kw): 
     self.__dict = kw 

    def __getattr__(self, name): 
     if not name.startswith('__'): 
      return self.__dict.get(name, '') 

print "i am an {0.error} example string {0.error2}".format(SafeFormat(hello=2,error2="success")) 
i am an example string success 
+1

Gracias. Es útil, pero como mencionó Fabian, no maneja objetos de mapeo que no sean dict –

18

str.format() no espera un objeto de asignación. Prueba esto:

from collections import defaultdict 

d = defaultdict(str) 
d['error2'] = "success" 
s = "i am an {0[error]} example string {0[error2]}" 
print s.format(d) 

Haces una defaultdict con una fábrica str() que devuelve "". Luego, crea una clave para el dictamen predeterminado. En la cadena de formato, accede a las claves del primer objeto pasado. Esto tiene la ventaja de permitirle pasar otras claves y valores, siempre y cuando su default es el primer argumento en format().

También, ver http://bugs.python.org/issue6081

+0

¿Se podría mejorar esto usando un objeto formateador (idea del enlace del informe de errores) en lugar de un error predeterminado? De esta forma, no se aplicará ningún cambio a la variable de formato. Gracias –

+0

formateador de clase (string.Formateador): def Get_Value (auto, llave, args, kwargs): Proveedores: si hasattr (clave "__ mod__"): argumentos de retorno [clave] otra cosa: kwargs retorno [clave] excepto: retorno "" Esto funciona para mí. La ventaja es que no es necesario crear un defecto de pago adicional. –

+0

Sí, eso funciona bien. No estoy seguro de cómo comparar la penalización de un defecto de pago adicional contra la penalización de un objeto + clase de formateador extra, pero en algunas situaciones podría ser mejor, especialmente si hace que el código sea más claro. –

2

Hice una versión que funciona de manera similar al método de Daniel, pero sin el {} 0.x acceso atributo.

import string  
class SafeFormat(object): 
    def __init__(self, **kw): 
     self.__dict = kw 

    def __getitem__(self, name): 
     return self.__dict.get(name, '{%s}' % name) 



string.Formatter().vformat('{what} {man}', [], SafeFormat(man=2)) 

imprime

'{what} 2' 
12

La solución oficial (Python 3 Docs) para cadenas en las asignaciones de formato es una subclase de la clase dict y definir la magia método __missing__(). Este método se llama cuando una clave no está presente, y lo que devuelve se utiliza para el formato de cadenas en su lugar:

class format_dict(dict): 
    def __missing__(self, key): 
     return "..." 

d = format_dict({"foo": "name"}) 

print("My %(foo)s is %(bar)s" % d) # "My name is ..." 

print("My {foo} is {bar}".format(**d)) # "My name is ..." 
+0

Acabo de intentarlo y puede hacer: 'alguna {cosa}'. Formato (formato_decir ('su': argumentos)) Silencia efectivamente el KeyError y reemplace la etiqueta por lo que devuelva la función mágica __missing__. – thomas

+1

'.format (** format_dict ({" foo ":" name "}))' se puede usar también, por supuesto. Sin embargo, su fragmento fallará debido a un error de sintaxis. El dict desempaquetado '**' es obligatorio para '.format()', no acepta dicts directamente. – CoDEmanX

+0

De hecho, mi error. – thomas

Cuestiones relacionadas