Como abrir um ficheiro com a instrução open with

estou a ver como fazer a entrada e saída de ficheiros em Python. Eu escrevi o seguinte código para ler uma lista de nomes (um por linha) de um arquivo para outro arquivo, ao verificar um nome com os nomes no arquivo e adicionar texto para as ocorrências no arquivo. O código funciona. Poderia ser melhor?

eu queria usar a declaração with open(... para ambos os ficheiros de entrada e saída, mas não consigo ver como eles podem estar no mesmo bloco, o que significa que eu teria de armazenar o nomes num local temporário.

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')
Author: marcospereira, 2012-02-14

4 answers

O Python permite colocar várias open() num único with. Separem-nos. Seu código seria então:

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 não, você não ganha nada colocando um explícito {[[3]} no final da sua função. Você pode usar return para sair mais cedo, mas você tinha-o no final, e a função vai sair sem ele. (Claro que com funções que devolvem um valor, você usa o return para especificar o valor a devolver.)

Usando vários open() itens com with foi não é suportado no Python 2.5 quando a Declaração with foi introduzida, ou no Python 2.6, mas é suportado no Python 2.7 e Python 3.1 ou mais recente.

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 está a escrever um código que deve ser executado em Python 2.5, 2.6 ou 3.0, anote as declarações with como as outras respostas sugeridas ou use contextlib.nested.

 326
Author: steveha, 2013-10-28 21:40:12

Usar blocos aninhados como este,

with open(newfile, 'w') as outfile:
    with open(oldfile, 'r', encoding='utf-8') as infile:
        # your logic goes right here
 30
Author: RanRag, 2018-07-06 20:05:50
Podes aninhar-te com blocos. Assim:
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)

Isto é melhor do que a sua versão porque garante que outfile será fechado mesmo que o seu código encontre excepções. Obviamente você poderia fazer isso com tentar/finalmente, mas with é a maneira certa de fazer isso.

Ou, como acabei de aprender, você pode ter vários gerentes de contexto em uma declaração Como descrito por @steveha. Parece-me uma opção melhor do que o ninho.

E para a tua final uma pergunta menor, o retorno não serve a nenhum propósito real. Eu removia-o.

 12
Author: David Heffernan, 2017-05-23 12:18:16

Às Vezes, você pode querer abrir uma quantidade variável de arquivos e tratar cada um o mesmo, você pode fazer isso com contextlib

from contextlib import ExitStack
filenames = [file1.txt, file2.txt, file3.txt]

with open('outfile.txt', 'a') as outfile:
    with ExitStack() as stack:
        file_pointers = [stack.enter_context(open(file, 'r')) for file in filenames]                
            for fp in file_pointers:
                outfile.write(fp.read())                   
 1
Author: brother-bilo, 2019-03-05 02:06:37