ouvrir lire et fermer un fichier en 1 ligne de code

128

Maintenant j'utilise:

pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()

Mais pour améliorer l'apparence du code, je peux faire:

output = open('pagehead.section.htm','r').read()

Lorsque vous utilisez la syntaxe ci-dessus, comment fermer le fichier pour libérer des ressources système?

1qazxsw2
la source
19
Il n'y a rien de plus attrayant en soi dans les monoplaces. Le code est lu beaucoup plus souvent qu'il n'est écrit, et devrait être écrit pour la compréhension, pas pour la «froideur». La seule exception est quand il y a un idiome bien connu dans une langue, mais je n'en connais pas dans ce cas.
drdwilcox
17
@drdwilcox: Les one-liners cryptiques sont mauvais, les one-liners déclaratifs sont bons. Il n'y a aucune raison (du moins je ne peux pas en voir une), pourquoi il n'y a pas de wrapper de fonction dans le noyau pour lire un fichier (un tel besoin courant) en un seul appel de fonction. Quelque chose comme contents = os.readfile(path). Si je voulais faire quelque chose de plus sophistiqué, alors d'accord, j'utiliserais volontiers with open(path) as fd: contents = fd.read(). Bien sûr, on peut écrire son propre wrapper, mais c'est à cela que sert le noyau, pour fournir l'utile aux abstractions aux programmeurs.
tokland
5
Il est vrai que le code est lu beaucoup plus qu'il n'est écrit, mais l'implication selon laquelle un code plus long est tout aussi bon qu'un code court ne peut pas être plus erronée. Si vous investissez du temps pour rendre votre code aussi court que possible (sans recourir à des astuces intelligentes difficiles à comprendre), cet investissement sera rentable à maintes reprises lorsque le code sera lu. Chaque ligne que vous écrivez ne rend pas service à quiconque lit votre code, vous devez donc vous efforcer d'écrire le moins possible. Souvenez-vous de la célèbre citation de Pascal: "J'ai allongé cette lettre uniquement parce que je n'ai pas eu le loisir de la raccourcir."
John Williams

Réponses:

195

Vous n'avez pas vraiment besoin de le fermer - Python le fera automatiquement pendant le ramasse-miettes ou à la sortie du programme. Mais comme @delnan l'a noté, il est préférable de le fermer explicitement pour diverses raisons.

Alors, que pouvez-vous faire pour rester bref, simple et explicite:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Maintenant, c'est juste deux lignes et assez lisible, je pense.

Tim Pietzcker
la source
2
@ 1qazxsw2 Si vous utilisez l' withinstruction, la ressource de fichier sera fermée correctement pour vous.
David Alber
13
Re première phrase: Python fermera par la suite . Mais cela ne signifie pas que vous devez oublier de fermer. Même avec refcounting, le fichier peut rester ouvert bien plus longtemps que vous ne le pensez et le souhaitez (par exemple, s'il est référencé par cycles). Cela se produit trois fois dans les implémentations Python qui ont un GC décent, où vous n'avez aucune garantie que quoi que ce soit soit GC à un moment donné. Même la documentation CPython indique que vous ne devriez pas compter sur GC pour un nettoyage comme celui-ci. La dernière partie de la réponse doit être en gras.
6
Si vous avez vraiment besoin d'un one-liner , il est possible de mettre la output = f.read()pièce sur la même ligne après le :.
Karl Knechtel
1
"ouvrir lire et fermer un fichier en 1 ligne de code" ceci fait deux lignes, et ne répond pas à la question.
user5359531
1
Cela dépend de la mise en œuvre - voir la réponse de Sven.
Tim Pietzcker
71

Le module Pathlib de la bibliothèque standard de Python fait ce que vous recherchez:

Path('pagehead.section.htm').read_text()

N'oubliez pas d'importer le chemin:

jsk@dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'

Sur Python 27, installez rétroporté pathliboupathlib2

Janusz Skonieczny
la source
8
Les autres réponses proposées withsont très bien, mais withc'est une déclaration, pas une expression. Cette pathlibréponse est la seule réponse à la question d'origine qui peut être intégrée dans une expression Python. Quelque chose commeSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael
24

En utilisant CPython, votre fichier sera fermé immédiatement après l'exécution de la ligne, car l'objet fichier est immédiatement récupéré. Il y a cependant deux inconvénients:

  1. Dans les implémentations Python différentes de CPython, le fichier n'est souvent pas immédiatement fermé, mais plutôt à un moment ultérieur, hors de votre contrôle.

  2. Dans Python 3.2 ou supérieur, cela lancera un ResourceWarning, s'il est activé.

Mieux vaut investir une ligne supplémentaire:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Cela garantira que le fichier est correctement fermé en toutes circonstances.

Sven Marnach
la source
17

Pas besoin d'importer de bibliothèques spéciales pour ce faire.

Utilisez la syntaxe normale et il ouvrira le fichier pour la lecture puis le fermera.

with open("/etc/hostname","r") as f: print f.read() 

ou

with open("/etc/hosts","r") as f: x = f.read().splitlines()

qui vous donne un tableau x contenant les lignes, et peut être imprimé comme ceci:

for line in x: print line

Ces one-liners sont très utiles pour la maintenance - essentiellement auto-documentés.

SDsolar
la source
8

Ce que vous pouvez faire est d'utiliser l' withinstruction et d'écrire les deux étapes sur une seule ligne:

>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content

L' withinstruction prendra soin d'appeler la __exit__fonction de l'objet donné même si quelque chose de mauvais s'est produit dans votre code; c'est proche de la try... finallysyntaxe. Pour l'objet renvoyé par open, __exit__correspond à la fermeture du fichier.

Cette déclaration a été introduite avec Python 2.6.

Joël
la source
Petite précision: selon la documentation a with été introduit dans Python 2.5, mais a dû être importé explicitement depuis __future__. Il est devenu disponible dans tous les contextes de Python 2.6.
David Alber
5

utilisez ilio : (inline io):

juste un appel de fonction au lieu de fichier open (), read (), close ().

from ilio import read

content = read('filename')
Iman
la source
2
with open('pagehead.section.htm')as f:contents=f.read()

la source
4
En quoi est-ce différent des 3 premières réponses?
Tous les travailleurs sont essentiels
4
La plus grande différence est qu'il n'y a qu'une seule ligne comme la question spécifiée. Personnellement, je ne peux pas en trouver au-delà, mais n'hésitez pas à critiquer mon travail plutôt que de contribuer vous-même à la question.
3
Le moyen le plus court et intégré pour ouvrir, lire et fermer un fichier en Python consiste à utiliser 2 lignes logiques, qu'elles soient condensées à 1 ligne ou non. Je ne pense donc pas que cette réponse soit effectivement différente des 3 réponses originales.
Tous les travailleurs sont essentiels
1
Peu importe si c'est «effectivement» différent. Je suis arrivé à cette page à la recherche d'une syntaxe à une ligne qui pourrait être utilisée avec python -cla ligne de commande, donc publier des réponses sur 2 lignes n'aide pas.
user5359531
1
@ user5359531 Je ne vois pas votre point: savez-vous que vous pouvez citer des expressions python avec ", utiliser ;pour ajouter deux instructions et supprimer une nouvelle ligne après :? L'expression suivante fonctionne très bien pour moi:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël
2

Je pense que le moyen le plus naturel pour y parvenir est de définir une fonction.

def read(filename):
    f = open(filename, 'r')
    output = f.read()
    f.close()
    return output

Ensuite, vous pouvez effectuer les opérations suivantes:

output = read('pagehead.section.htm')
Adrien Pavao
la source
0

Je fais souvent quelque chose comme ça lorsque j'ai besoin de quelques lignes entourant quelque chose que j'ai greffé dans un fichier journal:

$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54

$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5
Matthew Purdon
la source
1
Sans aucun rapport avec le sujet original, mais vous devriez regarder dans grep -A <n>, grep -B <n>et grep -C <n>, si elle est utile. Plus d'infos: stackoverflow.com/a/9083/1830159
Liam Stanley
0

En utilisant more_itertools.with_iter, il est possible d'ouvrir, lire, fermer et affecter un équivalent outputen une seule ligne (hors instruction d'importation):

import more_itertools as mit


output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))

Bien que possible, je chercherais une autre approche autre que d'assigner le contenu d'un fichier à une variable, c'est-à-dire une itération paresseuse - cela peut être fait en utilisant un withbloc traditionnel ou dans l'exemple ci-dessus en supprimant join()et en itérant output.

pylang
la source
Vous pouvez également importer dans le oneliner. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Cela fonctionne très bien et élimine le besoin d'une ligne pour l'importation.
melwil
1
Je suis complètement d'accord avec toi. Cependant, en discutant de la résolution de tâches avec des oneliners, je me suis souvent retrouvé dans des arguments où le résultat convenu devrait être une seule ligne de code collée dans un nouveau shell python. De tels défis sont rarement conformes à pep8. Ce n'est en aucun cas une bonne pratique pour écrire du code, c'était uniquement une astuce pour supprimer le besoin d'importations.
melwil
0

Si vous voulez que chaud et floue sentiment juste aller avec avec .

Pour python 3.6, j'ai exécuté ces deux programmes sous un nouveau départ d'IDLE, donnant des temps d'exécution de:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Donc pas beaucoup de différence.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: A: no 'with;
    c=[]
    start_time = time.time()
    c = open(inTextFile).read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

PRODUCTION:

OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: B: using 'with'
    c=[]
    start_time = time.time()
    with open(inTextFile) as D: c = D.read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

PRODUCTION:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
CopyPasteIt
la source