La fermeture explicite des fichiers est-elle importante?

149

En Python, si vous ouvrez un fichier sans appeler close(), ou fermez le fichier sans utiliser try- finallyou l' withinstruction " ", est-ce un problème? Ou est-il suffisant, en tant que pratique de codage, de s'appuyer sur le garbage collection Python pour fermer tous les fichiers? Par exemple, si on fait ça:

for line in open("filename"):
    # ... do stuff ...

... est-ce un problème parce que le fichier ne peut jamais être fermé et qu'une exception pourrait se produire et empêcher sa fermeture? Ou sera-t-il définitivement fermé à la fin de la fordéclaration parce que le dossier sort du cadre?

user553702
la source
13
Le fichier n'est pas hors de portée à la fin du forbloc. Son nombre de références ira à zéro, ce qui le fermera automatiquement, mais seules les fonctions, classes et modules définissent des portées en Python, pas d'autres instructions composées.
agf
18
Ce n'est pas un problème sauf si c'est un problème. Au niveau du système d'exploitation, tous les fichiers ouverts par le script seront fermés à la fermeture du script, vous n'avez donc pas à vous soucier de la fermeture des fichiers dans les scripts d'outils jetables. Cependant, les processus ont une limite sur le nombre de fichiers ouverts qu'ils peuvent conserver, de sorte que les scripts complexes ou de longue durée peuvent devoir être plus prudents. Dans tous les cas, c'est une bonne habitude de fermer vos fichiers.
Russell Borogove
3
@agf: Vous avez raison de dire que le fichier n'est pas hors de portée, mais ce n'est pas lié à la distinction entre les forblocs et les fonctions / classes / modules. C'est beaucoup plus simple que cela: les objets n'ont pas de portées, seuls les noms en ont. Il n'y a pas de nom qui fait référence à cet objet, donc il n'y a rien ici pour rester dans la portée ou sortir de la portée.
max
@max Mon commentaire corrige son hypothèse selon laquelle il existe une portée associée à la forboucle et mentionne que le fichier est fermé pour une raison entièrement différente. Cela n'entre pas dans les portées en Python, car ce n'est pas pertinent ici.
agf
@max, il y a une référence implicite portée à celle de la boucle for ... c'est un argument de sémantique
Peter R

Réponses:

126

Dans votre exemple, la fermeture du fichier n'est pas garantie avant la fermeture de l'interpréteur. Dans les versions actuelles de CPython, le fichier sera fermé à la fin de la boucle for car CPython utilise le comptage de références comme principal mécanisme de garbage collection, mais c'est un détail d'implémentation, pas une fonctionnalité du langage. Les autres implémentations de Python ne sont pas garanties de fonctionner de cette façon. Par exemple, IronPython, PyPy et Jython n'utilisent pas de comptage de références et ne fermeront donc pas le fichier à la fin de la boucle.

C'est une mauvaise pratique de s'appuyer sur l'implémentation du garbage collection de CPython car cela rend votre code moins portable. Vous n'aurez peut-être pas de fuites de ressources si vous utilisez CPython, mais si vous passez un jour à une implémentation Python qui n'utilise pas de comptage de références, vous devrez parcourir tout votre code et vous assurer que tous vos fichiers sont correctement fermés.

Pour votre exemple, utilisez:

with open("filename") as f:
     for line in f:
        # ... do stuff ...
Peter Graham
la source
8
L'utilisation with open() as fferme- t-elle automatiquement le fichier une fois terminé?
Rohan
25
@Rohan oui, c'est la petite magie que la withdéclaration fournit, mais bien sûr, pour que cette magie fonctionne, l'objet doit avoir les méthodes spéciales __enter__et __exit__, dans ce dernier, l'objet doit faire le closeet tout autre nettoyage qui doit être fait au fin de la withdéclaration ...
Copperfield
1
FYI: Cette réponse explique seulement "quand il serait fermé" mais n'explique pas "et s'il restait ouvert". Pour ce dernier, veuillez lire le "Que se passerait-il si un fichier reste ouvert?" partie dans cette réponse ( askubuntu.com/questions/701491/… )
RayLuo
De plus, ne pas fermer les fichiers peut entraîner des fichiers tronqués car le contenu des fichiers n'a pas été vidé.
Erwan Legrand
Donc, si je ne ferme pas le fichier, vais-je récupérer ma mémoire à coup sûr une fois le programme arrêté? Ou dois-je réellement quitter l'interprète entier?
Pro Q
22

Certains Pythons fermeront automatiquement les fichiers lorsqu'ils ne sont plus référencés, tandis que d'autres ne le feront pas et c'est à l'O / S de fermer les fichiers lorsque l'interpréteur Python se termine.

Même pour les Pythons qui fermeront les fichiers pour vous, le timing n'est pas garanti: cela pourrait être immédiat, ou cela pourrait être quelques secondes / minutes / heures / jours plus tard.

Ainsi, même si vous ne rencontrez pas de problèmes avec le Python que vous utilisez, ce n'est certainement pas une bonne pratique de laisser vos fichiers ouverts. En fait, dans cpython 3, vous recevrez maintenant des avertissements indiquant que le système devait fermer des fichiers pour vous si vous ne le faisiez pas.

Morale: nettoyez après vous. :)

Ethan Furman
la source
9
Les fichiers sont fermés lorsqu'ils ne sont plus référencés dans CPython, mais ce n'est pas une fonctionnalité de langage. Si c'était le cas, vous pourriez vous y fier.
Peter Graham
9

Bien qu'il soit tout à fait sûr d'utiliser une telle construction dans ce cas particulier, il existe quelques mises en garde pour généraliser une telle pratique:

  • run peut potentiellement manquer de descripteurs de fichiers, bien que peu probable, imaginez chasser un bogue comme celui-là
  • vous ne pourrez peut-être pas supprimer ledit fichier sur certains systèmes, par exemple win32
  • si vous exécutez autre chose que CPython, vous ne savez pas quand le fichier est fermé pour vous
  • si vous ouvrez le fichier en mode écriture ou lecture-écriture, vous ne savez pas quand les données sont vidées
Dima Tisnek
la source
3

Le fichier est récupéré et donc fermé. Le GC détermine quand il est fermé, pas vous. De toute évidence, ce n'est pas une pratique recommandée car vous pourriez atteindre la limite de descripteur de fichier ouvert si vous ne fermez pas les fichiers dès que vous avez fini de les utiliser. Et si dans votre forboucle, vous ouvrez plus de fichiers et les laissez en attente?

Nam Nguyen
la source
Mais si vous ouvriez d'autres fichiers dans cette boucle for, il serait toujours possible qu'il y ait plus d'un fichier ouvert simultanément, que vous fermiez explicitement l'un d'entre eux ou non. Êtes-vous en train de dire que le fichier n'est pas nécessairement récupéré dès que le fichier est hors de portée, il serait donc fermé plus tôt si cela était fait explicitement? Qu'en est-il lorsqu'une exception se produit (lorsque vous utilisez avec / try-finally vs ne pas le faire)?
user553702
1
Dans CPython, le comptage des références entraînera sa collecte après l' forinstruction - vous n'aurez pas à attendre la prochaine exécution de garbage collection.
agf
3

Salut Il est très important de fermer votre descripteur de fichier dans la situation où vous allez utiliser son contenu dans le même script python. Aujourd'hui, je me rends compte après un débogage si long. La raison en est que le contenu ne sera modifié / supprimé / enregistré qu'après la fermeture du descripteur de fichier et les modifications sont affectées au fichier!

Supposons donc que vous ayez une situation où vous écrivez du contenu dans un nouveau fichier, puis sans fermer fd, vous utilisez ce fichier (et non fd) dans une autre commande shell qui lit son contenu. Dans cette situation, vous n'obtiendrez pas le contenu de la commande shell comme prévu et si vous essayez de déboguer, vous ne pouvez pas trouver facilement le bogue. vous pouvez également en lire plus dans mon article de blog http://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.html

Zeel Shah
la source
1

Pendant le processus d'E / S, les données sont mises en mémoire tampon: cela signifie qu'elles sont conservées dans un emplacement temporaire avant d'être écrites dans le fichier.

Python ne vide pas la mémoire tampon, c'est-à-dire n'écrit pas les données dans le fichier, tant qu'il n'est pas certain que vous avez fini d'écrire. Une façon de procéder consiste à fermer le fichier.

Si vous écrivez dans un fichier sans fermer, les données ne parviendront pas au fichier cible.

Sanket Nagrale
la source