Progettazione di una funzione con molti componenti opzionali

5

Sto cercando di capire una buona pratica per la progettazione di una funzione con (molti) componenti opzionali.

Per un esempio specifico, dì che sono interessato a progettare una funzione feature extractor che prende come input un documento e restituisce un elenco di funzionalità estratte dal documento.

Domanda

Se ci sono molti componenti opzionali, quale tipo di approccio sarebbe considerato di buona pratica e scalabile?

Qui di seguito sono un paio di opzioni che sono stato in grado di pensare, anche se potrebbero esserci altri approcci che non ho considerato.

Metodo 1: basato sulla classe

class FeatureExtractor(object):
    """Extract features from text for use in classification."""
    def __init__(self, term_frequency=False, consider_negation=False,
                 pos_tags=False):
        self.term_frequency = term_frequency
        self.consider_negation = consider_negation
        self.pos_tags = pos_tags
        # Could be many more ...

    def extract(self, document):
        """Extract features from a document."""
        features = []
        if self.term_frequency:
            features.extend(self.extract_term_frequency(document))
        if self.consider_negation:
            features.extend(self.extract_negation(document))
        if self.pos_tags:
            features.extend(self.extract_pos_tags(document))
        return features

    def extract_term_frequency(self, document):
        pass

    def extract_negation(self, document):
        pass

    def extract_pos_tags(self, document):
        pass

extractor = FeatureExtractor(term_frequency=True, consider_negation=True,
                             pos_tags=True)
extractor.extract(document)

Approccio 2: argomenti della funzione

def extract(document, *functions):
    """Extract features from a document."""
    features = []
    for function in functions:
            features.extend(function(document))
    return features

def extract_term_frequency(document):
    pass

def extract_negation(document):
    pass

def extract_pos_tags(document):
    pass

extract(document, extract_term_frequency, extract_negation, extract_pos_tags)

Approccio 3: classe con mixin o eredità multipla

Qualcosa di una combinazione del primo e del secondo approccio, anche se non sono sicuro di come sarebbe stato fatto.

Qualche idea su una direzione da affrontare sarebbe molto apprezzata!

    
posta Wesley Baugh 04.03.2013 - 03:12
fonte

2 risposte

2

Penso che la domanda centrale che dovresti porci qui sia "che tipo di caratteristiche ti aspetti di estrarre da un documento"?

Se vuoi essere in grado di aggiungere facilmente nuove funzioni di estrattore di feature, vai alla seconda versione, in cui ciascuna funzione viene estratta in modo indipendente e gestisce il documento da solo.

D'altra parte, se conosci in anticipo quale tipo di funzionalità hai bisogno, usa un estrattore centrale che sfrutta tale conoscenza per estrarre tutto in una volta (usando i parametri per ottimizzare le funzionalità, ofc)

Per quanto riguarda le classi vs le funzioni, onestamente non penso che siano troppo diverse l'una dall'altra, poiché alla fine incapsulano le cose allo stesso modo. Nel caso di Python raccomanderei l'uso di "callables" quando possibile (quindi è possibile utilizzare le funzioni o gli oggetti che definiscono __call__ dove appropriato) e userei sempre le funzioni sulle classi a meno che non debba tenere traccia di qualche stato interno extra (chiusure Python succhiare a causa dell'ambito locale per impostazione predefinita)

    
risposta data 04.03.2013 - 16:53
fonte
1

Con quello che mostri lì preferisco gli argomenti della funzione perché c'è meno codice coinvolto per andare male. Userei ancora un qualche tipo di lezione per unirmi a loro.

Tuttavia, se implementassi un sistema come questo, sarei molto meno legato all'implementazione. Non sono sicuro di cosa intendi per "caratteristiche estratte da un documento" ma immaginiamo che il documento fosse la specifica per un'automobile e accenna che ha cerchi in lega, funziona a benzina o diesel e così via. Se volessi estrarre quei dati, a seconda che avessi voglia di approcciare le cose da una prima caratteristica o prima di un documento, penserei di creare una raccolta delle caratteristiche che mi interessavano o una raccolta delle caratteristiche che avrei potuto estrai dal documento.

Nel primo caso potrei dire:

def featuresILike = { "alloy wheels":"/alloy wheels/", "v8 engine":"/V8/" } and so on.

Quindi posso solo scorrere il documento alla ricerca di corrispondenze con questi modelli e aggiungere la chiave correlata a questi documenti con i metadati se trovo questo.

Nel secondo caso potrei cercare il modello che indica un elenco di funzionalità, quindi provare a estrarre tutte le funzionalità elencate in un particolare documento nei metadati. In questo modo posso solo eseguire una query su tutti loro se necessario.

La differenza concettuale con questo tipo di approccio è che il mio obiettivo è trattare i dati come dati e quindi utilizzare il mio codice per estrarlo. Ogni volta che scrivo una funzione di tipo "hasAlloyWheels ()" quello che sto facendo è rendere i miei dati in codice. A volte potresti doverlo fare, ma se riesci a estrarre tali informazioni nella configurazione o a restringere il tuo codice in modo che avvenga solo in un paio di punti, ti ritroverai con qualcosa che è più riutilizzabile e più facile da mantenere .

    
risposta data 04.03.2013 - 16:44
fonte

Leggi altre domande sui tag