2012-09-25 20 views
13

Se una funzione prende come input il nome di un file di testo, posso rifattorizzarlo per prendere invece un oggetto file (lo chiamo "stream"; c'è una parola migliore?). I vantaggi sono evidenti - una funzione che prende un flusso come argomento è:nome file vs oggetto file come argomento di funzione

  • molto più facile scrivere un test di unità per, dal momento che non ho bisogno di creare un file temporaneo solo per il test
  • più flessibile, dal momento che posso utilizzarlo in situazioni in cui in qualche modo ho già il contenuto del file in una variabile

Ci sono degli svantaggi nei flussi? O dovrei sempre refactificare una funzione da un argomento nome file ad un argomento stream (assumendo, ovviamente, il file è solo testo)?

risposta

4

Esistono numerose funzioni nella libreria standard python che accettano entrambe stringhe che sono nomi di file o oggetti di file aperti (presumo che sia ciò a cui ti stai riferendo come "flusso"). Non è davvero difficile creare un decoratore che tu possa utilizzare per far sì che le tue funzioni accettino l'uno o l'altro.

Uno svantaggio grave nell'usare "flussi" è che lo si passa alla funzione e quindi la funzione legge da esso, modificando effettivamente lo stato. A seconda del programma, il ripristino di tale stato potrebbe essere complicato se necessario. (Ad esempio, potrebbe essere necessario disordine che codice con f.tell() e poi f.seek().)

+0

Sì, quando ho detto "stream", intendevo "open file object". Non sarebbe possibile scrivere un decoratore che salva e ripristina lo stato del flusso? – max

+0

E non c'è un modo per creare una copia economica di uno stream, in modo tale che la copia possieda il proprio "puntatore", mentre il "puntatore" del flusso originale rimane intatto? Sarebbe ancora più pulito rispetto all'approccio di salvataggio/ripristino dello stato. – max

+0

@max - Certo, potresti scrivere un decoratore per farlo. L'importante è documentare quando stai ripristinando lo stato e quando non lo sei. Per quanto riguarda la creazione di una copia, l'unica cosa che mi viene in mente è 'itertools.tee', che è un po 'diversa (ma è molto oltre la normale ora di andare a letto, quindi non garantisco nulla che scrivo in questo momento: ^). – mgilson

5

... Ecco come modulo xml.etree.ElementTree implementa la funzione parse:

def parse(self, source, parser=None): 
    close_source = False 
    if not hasattr(source, "read"): 
     source = open(source, "rb") 
     close_source = True 
    ... 

Come il nome del file è una stringa, non ha il metodo read() (qui qualsiasi attributo di quel nome è spuntato); tuttavia, il file aperto ce l'ha. Le quattro linee rendono comune il resto del codice. L'unica complicazione è che devi ricordare se chiudere l'oggetto file (qui chiamato source) o no. Se era all'interno di open, allora deve essere chiuso. Altrimenti, non deve essere chiuso.

In realtà, i file differiscono leggermente dai sorsi. Gli stream sono potenzialmente infiniti mentre i file di solito no (a meno che qualche dispositivo sia mappato come se fosse un file). La differenza importante durante l'elaborazione è che non puoi mai leggere il flusso in memoria in una sola volta. Devi elaborarlo per blocchi.

+0

Stavo cercando un'implementazione di riferimento su questo nello stdlib. Grazie per lo snippet, fa davvero risparmiare tempo. Darei un altro +1 per l'avvertimento per pezzi se potessi. – n611x007

Problemi correlati