2010-08-21 25 views
15

C'è un modo per utilizzare python string.format in modo che non venga generata alcuna eccezione quando manca un indice, invece viene inserita una stringa vuota.python string format sopprimi/silent keyerror/indexerror

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

qui, risultato dovrebbe essere:

"i am an example string success" 

In questo momento, Python lancia un KeyError e ferma la formattazione. È possibile modificare questo comportamento?

Grazie

Edit:

Esiste Template.safe_substitute (anche che lascia intatto il modello invece di inserire una stringa vuota), ma non poteva qualcosa di simile per string.format

L' il comportamento desiderato sarebbe simile alla sostituzione delle stringhe in 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 "" 

Questo sembra fornire il comportamento desiderato.

+0

È possibile anche usare 'str.format_map()', come descritto in [questa risposta] (http://stackoverflow.com/a/17215533/877069). –

risposta

5

Sfortunatamente, no, non esiste un modo per farlo per impostazione predefinita. Tuttavia è possibile fornire defaultdict o un oggetto con override __getattr__, e utilizzare in questo modo:

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

Grazie. La sua userful, ma come menzionato da Fabian, non gestisce oggetti di mappatura diversi da dict –

18

str.format() non si aspetta un oggetto di mapping. Prova questo:

from collections import defaultdict 

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

Si effettua una defaultdict con una fabbrica str() che restituisce "". Quindi fai una chiave per il defaultdict. Nella stringa di formato, si accede alle chiavi del primo oggetto passato. Questo ha il vantaggio di permetterti di passare altre chiavi e valori, a patto che defaultdict sia il primo argomento a format().

Inoltre, vedere http://bugs.python.org/issue6081

+0

Questo potrebbe essere migliorato usando un oggetto formattatore (idea dal link del bug report) invece di un defaultdict? in questo modo, nessuna modifica può essere reqd alla variabile di formato. Grazie Formattatore classe –

+0

(stringa.Formatter): def Get_Value (auto, chiave, args, kwargs): provare: se hasattr (chiave, "__ mod__"): args di ritorno [tasto] altro: kwargs di ritorno [tasto] eccezione: ritorno "" Questo funziona per me. Il vantaggio è che non è necessario creare un extra defaultdict. –

+0

Sì, funziona bene. Non sono sicuro di come confrontare la penalità di un extra defaultdict contro la penalità di un oggetto extra di classe Formatter +, ma in alcune situazioni potrebbe essere migliore, specialmente se rende il codice più chiaro. –

2

ho fatto una versione che funziona in modo simile al metodo di Daniel, ma senza il {} 0.x accesso attributo.

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)) 

stampe fuori

'{what} 2' 
12

La soluzione ufficiale (Python 3 Docs) per archi in mappature formato è alla sottoclasse la classe dict e per definire la magia metodo __missing__(). Questo metodo viene chiamato ogni volta che un tasto non è presente, e ciò che ritorna è usato per formattare la stringa invece:

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

Ho appena provato questo e puoi fare: 'some {thing}'. Format (format_dict ('your': argomenti)) Silenzia efficacemente il KeyError e sostituisce il tag con qualunque cosa restituisca la funzione magica __missing__. – thomas

+1

'. Formattare (** format_dict ({" foo ":" nome "}))' può essere usato anche, naturalmente. Tuttavia, lo snippet non riuscirà a causa di un errore di sintassi. Il dict decompressione '**' è obbligatorio per '.format()', non accetta direttamente dict. – CoDEmanX

+0

Anzi, mio ​​errore. – thomas