251 votes

Comment ouvrir un fichier à l'aide de l'instruction "Ouvrir avec" ?

Je cherche à savoir comment faire de l'entrée et de la sortie de fichiers en Python. J'ai écrit le code suivant pour lire une liste de noms (un par ligne) d'un fichier vers un autre fichier tout en vérifiant un nom par rapport aux noms du fichier et en ajoutant du texte aux occurrences dans le fichier. Ce code fonctionne. Pourrait-on faire mieux ?

Je voulais utiliser le with open(... pour les fichiers d'entrée et de sortie, mais je ne vois pas comment ils pourraient être dans le même bloc, ce qui signifie que je devrais stocker les noms dans un emplacement temporaire.

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')

374voto

steveha Points 24808

Python permet de mettre plusieurs open() dans un seul with . Vous les séparez par une virgule. Votre code serait alors :

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')

Et non, vous ne gagnez rien à mettre une explicite return à la fin de votre fonction. Vous pouvez utiliser return pour sortir prématurément, mais vous l'aviez à la fin, et la fonction sortira sans elle. (Bien sûr, avec les fonctions qui renvoient une valeur, vous utilisez la fonction return pour spécifier la valeur à renvoyer).

Utilisation de plusieurs open() articles avec with n'était pas pris en charge dans Python 2.5 lorsque l'option with a été introduite, ou dans Python 2.6, mais elle est prise en charge dans Python 2.7 et Python 3.1 ou plus récent.

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

Si vous écrivez du code qui doit s'exécuter en Python 2.5, 2.6 ou 3.0, imbriquez la balise with comme les autres réponses l'ont suggéré ou utiliser contextlib.nested .

37voto

RanRag Points 9395

Utilisez des blocs imbriqués comme ceci,

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

14voto

David Heffernan Points 292687

Vous pouvez les emboîter avec des blocs. Comme ça :

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)

C'est mieux que votre version car vous garantissez que outfile sera fermé même si votre code rencontre des exceptions. Évidemment, vous pourriez faire cela avec try/finally, mais with est la bonne façon de procéder.

Ou, comme je viens de l'apprendre, vous pouvez avoir plusieurs gestionnaires de contexte dans une instruction with comme décrit par @steveha . Cela me semble être une meilleure option que l'imbrication.

Et pour votre dernière question mineure, le retour ne sert à rien. Je le supprimerais.

1voto

brother-bilo Points 280

Parfois, vous pouvez ouvrir un nombre variable de fichiers et les traiter tous de la même manière. 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())

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X