2012-02-14 7 views
113

Sto guardando come eseguire l'input e l'output di file in Python. Ho scritto il seguente codice per leggere un elenco di nomi (uno per riga) da un file in un altro file mentre si controlla un nome con i nomi nel file e aggiungendo il testo alle occorrenze nel file. Il codice funziona. Potrebbe essere fatto meglio?Come aprire un file usando l'istruzione open con

Avrei voluto utilizzare l'istruzione with open(... per entrambi i file di input e di output, ma non posso vedere come potrebbero essere nello stesso blocco, il che significa che avrei bisogno di memorizzare i nomi in una posizione temporanea.

def filter(txt, oldfile, newfile): 
    '''\ 
    Read a list of names from a file line by line into an output file. 
    If a line begins with a particular name, insert a string of text 
    after the name before appending the line to the output file. 
    ''' 

    outfile = open(newfile, 'w') 
    with open(oldfile, 'r', encoding='utf-8') as infile: 
     for line in infile: 
      if line.startswith(txt): 
       line = line[0:len(txt)] + ' - Truly a great person!\n' 
      outfile.write(line) 

    outfile.close() 
    return # Do I gain anything by including this? 

# input the name you want to check against 
text = input('Please enter the name of a great person: ')  
letsgo = filter(text,'Spanish', 'Spanish2') 
+0

"significato che avrei bisogno di memorizzare i nomi in una posizione temporanea"? Puoi spiegare cosa intendi con questo? –

+2

Nota che 'filter()' è [una funzione built-in] (https://docs.python.org/2/library/functions.html#filter) e quindi probabilmente dovresti scegliere un nome diverso per la tua funzione. – Tom

+0

@Tom fa una funzione nel namespace sovrascrive la funzione built-in? – UpTide

risposta

195

Python permette di mettere più open() dichiarazioni in un unico with. Tu virgola-li separa. Il tuo codice sarebbe allora:

def filter(txt, oldfile, newfile): 
    '''\ 
    Read a list of names from a file line by line into an output file. 
    If a line begins with a particular name, insert a string of text 
    after the name before appending the line to the output file. 
    ''' 

    with open(newfile, 'w') as outfile, open(oldfile, 'r', encoding='utf-8') as infile: 
     for line in infile: 
      if line.startswith(txt): 
       line = line[0:len(txt)] + ' - Truly a great person!\n' 
      outfile.write(line) 

# input the name you want to check against 
text = input('Please enter the name of a great person: ')  
letsgo = filter(text,'Spanish', 'Spanish2') 

E no, non si guadagna nulla, mettendo un esplicito return al termine della funzione. Puoi usare return per uscire presto, ma alla fine ce l'hai, e la funzione uscirà senza di essa. (Naturalmente con funzioni che restituiscono un valore, si utilizza il return per specificare il valore da restituire.)

Utilizzando multipla open() oggetti con with non è stato supportato in Python 2.5, quando è stata introdotta la dichiarazione with, o in Python 2.6, ma è supportato in Python 2.7 e Python 3.1 o successivi.

http://docs.python.org/reference/compound_stmts.html#the-with-statement http://docs.python.org/release/3.1/reference/compound_stmts.html#the-with-statement

Se si sta scrivendo codice che deve correre in Python 2.5, 2.6 o 3.0, nidificano le with dichiarazioni come le altre risposte suggerita o utilizzare contextlib.nested.

8

È possibile annidare i blocchi. Come questo:

with open(newfile, 'w') as outfile: 
    with open(oldfile, 'r', encoding='utf-8') as infile: 
     for line in infile: 
      if line.startswith(txt): 
       line = line[0:len(txt)] + ' - Truly a great person!\n' 
      outfile.write(line) 

Questo è meglio che la tua versione, perché vi garantisco che outfile sarà chiusa, anche se il codice incontra eccezioni. Ovviamente è possibile farlo con try/finally, ma with è il modo giusto per farlo.

Oppure, come ho appena appreso, è possibile avere più gestori di contesto in a con istruzione come described by @steveha. Mi sembra un'opzione migliore del nesting.

E per la tua domanda secondaria finale, il reso non ha uno scopo reale. Lo rimuoverei.

+0

Grazie, molto. Ci proverò e accetterò la tua risposta se/quando riuscirò a farlo funzionare. – Disnami

+0

Grazie ancora. Devo aspettare sette minuti prima che io possa accettare. – Disnami

+5

@Disnami assicurati di accettare la risposta giusta (e non è questa!) ;-) –

18

utilizzare i blocchi annidati come questo,

with open(newfile, 'w') as outfile: 
    with open(oldfile, 'r', encoding='utf-8') as infile: 
    #your logic goes here 
Problemi correlati