2010-10-20 13 views
5

Sono relativamente nuovo a Python e vorrei sapere se sto reinventando una ruota o faccio le cose in modo non piti- co - ho letto male.Dichiarazione switch-like basata sul dizionario con azioni

Sto riscrivendo un parser originariamente scritto in Lua. Esiste una funzione che accetta un nome di campo dalla tabella importata e il suo valore, esegue alcune azioni sul valore e lo memorizza nel dizionario di destinazione con un nome di chiave appropriato.

Nel codice originale è risolto da una lunga istruzione tipo switch con funzioni anonime come azioni. codice Python è simile al seguente:

class TransformTable: 
    target_dict = {} 
    ... 
    def mapfield(self, fieldname, value): 
     try: 
      { 
       'productid': self.fn_prodid, 
       'name': self.fn_name, 
       'description': self.fn_desc, 
       ... 
      }[fieldname](value) 
     except KeyError: 
      sys.stderr.write('Unknown key !\n') 

    def fn_name(val): 
     validity_check(val) 
     target_dict['Product'] = val.strip().capitalize() 
    ... 

funzione Ogni "campo-handler" fa diverse azioni e negozi in chiavi diverse in target_dict, naturalmente. Dato che Python non supporta funzioni anonime con istruzioni (o mi sono perso qualcosa?) Le funzioni devono essere scritte separatamente, il che rende il codice meno leggibile e inutilmente complicato.

Qualsiasi suggerimento su come svolgere tali compiti in un modo più elegante e più sdolcinato è apprezzato.

Thx

David

+0

Si potrebbe anche voler fare uno sforzo per evitare di reinventare la domanda cercando qui simili prima di postarne uno. – martineau

risposta

0

Ho applicato un approccio simile a @Matti Virkkunen'a qualche tempo fa nel mio answer a una domanda dal titolo "switch case in python doesn't work; need another pattern". Dimostra anche un modo relativamente facile e aggraziato di gestire campi sconosciuti. Trasformato in termini nel tuo esempio, sarebbe simile a questo:

class TransformTable: 
    target_dict = {} 

    def productid(self, value): 
     ... 
    def name(self, value): 
     validity_check(value) 
     self.target_dict['Product'] = value.strip().capitalize() 
    def description(self, value): 
     ... 

    def _default(self, value): 
     sys.stderr.write('Unknown key!\n') 

    def __call__(self, fieldname, value): 
     getattr(self, fieldname, self._default)(value) 

transformtable = TransformTable() # create callable instance 

transformtable(fieldname, value) # use it 
+1

Questa è una soluzione un po 'più pulita. Grazie. Quanto bene funzionerebbe se i nomi dei campi (estratti dalla tabella di importazione) conterranno caratteri unicode (con segno diacritico), vale a dire. definire le funzioni con nomi non ASCII? –

+0

Per utilizzare il meccanismo mostrato è necessario un qualche tipo di mappatura da quello che viene acceso al nome dell'identificatore valido. Sopra di esso si presuppone che sia 1: 1. Un altro modo più generale di gestirlo sarebbe avere un dizionario separato o una tabella di ricerca che mappa ogni input valido ('fieldname' qui) al nome del metodo univoco - che potrebbe essere semplicemente' method1', 'method2', ecc. su valori interi, hai qualcosa come, '' case_ '+ str (numero) '. La mappatura non deve essere 1: 1, nel senso che diversi input potrebbero essere tutti gestiti dallo stesso metodo, ad esempio. Sei libero di personalizzarlo come preferisci. – martineau

+0

Thx per chiarimenti. Quindi la mia soluzione originale con mappatura 1: 1 per dizionario nella sezione di prova era vicina a questo. –

1

Se con ogni mezzo possibile, si potrebbe nominare le funzioni membro in base ai nomi dei campi e solo fare qualcosa di simile:

getattr(self, "fn_" + fieldname)(value) 

Edit: e si può utilizzare hasattr per verificare se la funzione esiste, invece di prevedere un KeyError. O aspettarsi un AttributeError. In ogni caso, dovresti inserire solo l'accesso all'interno del tuo try..except e chiamarlo all'esterno, poiché altrimenti un KeyError causato all'interno di uno dei metodi del campo potrebbe essere frainteso.

+0

Belle idee con generalizzazione dei nomi di funzioni. –

+0

Belle idee con generalizzazione dei nomi di funzioni. C'è anche un modo più generale di dizionario -> mappature del dizionario (chiave per la chiave con trasformazione del valore)? –

+0

Penso che questo sia il modo standard per attivare le stringhe in un contesto di classe. Sono troppo pigro per trovare il collegamento ma so che Guido l'ha definito una soluzione molto elegante. Lui è olandese quindi l'unica strada giusta è immediatamente ovvia per lui. – aaronasterling

Problemi correlati