2011-08-19 11 views
5

Recentemente ho fatto un sacco di programmazione musicale basata, e come tale ritrovo a fare questo genere di cose molto a che fare con i metadati mancante in alcuni brani:String formattazione in pitone

default = {'title': 'Unknown title', 'artist': 'unknown Artist'} 
default.update(song) 
print '{title} - {artist}'.format(**default) 

C'è un modo più pulito per fare questo? Ho provato imperativi __missing__ in questo modo, ma mancano ancora le chiavi gettano un KeyError:

class Song(dict): 
    # dictionary with some nice stuff to make it nicer 

    def __missing__(self, key): 
     return 'Unknown {key}'.format(key = key) 

Edit: Scusa avrei dovuto essere più chiaro, in sostanza il seguente deve lavorare.

s = Song() 
print '{notAKey}'.format(s) 

Un paio di persone hanno sottolineato che i ** s non sono necessari.

Modifica 2: Ho "risolto" il mio problema, almeno con mia soddisfazione. È discutibile se questo sia più o meno pulito, ma funziona per me.

from string import Formatter 

class DefaultFormatter(Formatter): 

    def get_value(self, key, args, kwargs): 
     # Try standard formatting, then return 'unknown key' 

     try: 
      return Formatter.get_value(self, key, args, kwargs) 
     except KeyError: 
      return kwargs.get(key, 'Unknown {0}'.format(key)) 

class Song(dict): 

    def format(self, formatString): 
     # Convenience method, create a DefaultFormatter and use it 

     f = DefaultFormatter() 
     return f.format(formatString, **self) 

Così il seguente tornerà 'notAKey Unknown'

k = Song() 
print k.format('{notAKey}') 
+0

Solo una piccola raccomandazione: sembra che tu stia facendo un'applicazione per l'uso quotidiano e magari la distribuisci. Se lo farai, allora dovresti iniziare a usare [gettext] (http://docs.python.org/library/gettext.html) - ti risparmierai molto dopo. – nagisa

risposta

-1

io preferisco la versione di Jared, ma se si vuole veramente per la sua attuazione da soli, qui è un modo:

>>> class Song(dict): 
...  def __getitem__(self, key): 
...    if key in self.keys(): return super(Song, self).__getitem__(key) 
...    return 'Unknown {key}'.format(key=key) 
... 
>>> s = Song() 
>>> s['foo'] 
'Unknown foo' 
>>> s['foo'] = 1 
>>> s['foo'] 
1 
+0

+1 per mostrare come implementarlo da soli, se hai bisogno di ulteriore personalizzazione. –

+0

La chiave 'in self.keys()' trasforma un'operazione O (1) in O (n). Inoltre, i newline sono gratuiti. – habnabit

+0

Questo ** non funziona ** perché '** foo' converte la cosa passata in un normale dettato. L'hai testato sul caso reale? –

3

Warning: This solution does not actually work to solve the original question regarding '{title} - {artist}'.format(**default)

Hai provato a importare defaultdict da collections?

from collections import defaultdict 

class Song(defaultdict): 
    def __missing__(self, key): 
     return 'Unknown {key}'.format(key = key) 

Ecco una domanda simile: How to make a python dictionary that returns key for keys missing from the dictionary instead of raising KeyError?:

+0

Questo ** non funziona ** per lo stesso motivo per cui il secondo snippet di OP non funziona. Non so perché pensi che funzionerebbe. L'hai provato mentre passavi ancora "** your_instance"? –

-1

Beh, un'opzione mi viene in mente sta usando un metodo che intrinsecamente si può fornire con i valori di default, vale a dire getattr. Se desideri trasformare il vostro dict in un oggetto trasformando chiavi in ​​attributi, è possibile utilizzare la cassaforte getattr a prelevare valori:

class AttributeDict(): 
    def __init__(self, source_dict): 
     self._ATTRIBUTE_DICT_source_dict = source_dict 
     for key in source_dict.keys(): 
      setattr(self, str(key), source_dict[key]) 

Ora si può semplicemente utilizzare:

song = AttributeDict(song) 
artist = getattr(song, 'artist', 'Unknown Artist') 
6

Sintesi: incapsula la canzone in una classe.

Mi sembra che una canzone sia un tipo di dati primario nel codice ed è degna di avere una classe dedicata per rappresentarla. Con tutti i mezzi usa un ditt interno alla classe per archiviare i dati, ma cerca di passare a un livello più alto di astrazione rispetto a un dittico.

Si dovrebbe mirare a questa classe per fornire tutti i servizi necessari per supportare le operazioni che si eseguono sui brani. Inserisci tutto il codice di formattazione nella classe in modo che non sia sparsi sul tuo codice che utilizza gli elementi del brano. In effetti troverai tutti i tipi di operazioni che vogliono diventare metodi di questa classe.

Per quanto riguarda l'implementazione della formattazione, non importa se è un po 'prolisso poiché lo si scrive in un solo posto.

1

Sfortunatamente, quando si chiama un metodo con la sintassi **foo, si sta convertendo foo solo in un dettato regolare.La soluzione più pulita è probabilmente quella che hai pubblicato nel tuo primo frammento.

+0

Buon punto. Preferisco la lezione di prima classe. – leoluk