web-dev-qa-db-fra.com

Comment ouvrir un fichier en utilisant l'instruction open with

Je regarde comment faire l'entrée et la sortie de fichier en Python. J'ai écrit le code suivant pour lire une liste de noms (un par ligne) d'un fichier dans un autre fichier tout en comparant un nom aux noms du fichier et en ajoutant du texte aux occurrences du fichier. Le code fonctionne. Pourrait-il être mieux fait?

J'aurais voulu utiliser l'instruction with open(... pour les fichiers d'entrée et de sortie, mais je ne voyais pas comment ils pourraient être dans le même bloc, ce qui signifierait 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')
179
Disnami

Python permet de mettre plusieurs instructions open() dans une seule with. Vous les séparez par des virgules. 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 en mettant un return explicite à la fin de votre fonction. Vous pouvez utiliser return pour quitter tôt, mais vous l’aviez à la fin et la fonction se fermerait sans elle. (Bien sûr, avec les fonctions qui renvoient une valeur, vous utilisez le return pour spécifier la valeur à renvoyer.)

L'utilisation de plusieurs éléments open() avec with n'était pas prise en charge dans Python 2.5 lorsque l'instruction with ou dans Python 2.6 a été introduite. est supporté dans Python 2.7 et Python 3.1 ou plus récent.

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

Si vous écrivez du code qui doit être exécuté dans Python 2.5, 2.6 ou 3.0, imbriquez les instructions with comme les autres réponses suggérées ou utilisez contextlib.nested .

282
steveha

Utilisez des blocs imbriqués comme celui-ci,

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

Vous pouvez faire votre nid 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 pouvez le faire avec try/finally, mais with est la bonne façon de le faire.

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

Et pour votre dernière question mineure, le retour ne sert à rien. Je l'enlèverais.

11
David Heffernan

Parfois, vous voudrez peut-être ouvrir un nombre variable de fichiers et les traiter de la même façon, vous pouvez le faire avec 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
brother-bilo