11
votes

Fichier ouvert: Ce mauvais style Python est-il?

lire le contenu d'un fichier: xxx

Le fichier ouvert s'arrête immédiatement en étant référencé n'importe où, de sorte que l'objet de fichier finira par fermer ... et cela ne devrait pas affecter d'autres programmes en l'utilisant. , puisque le fichier n'est ouvert que pour la lecture, ne pas écrire.

Edit: Cela m'a effectivement mordu dans un projet que j'ai écrit - cela m'a incité à demander Cette question. Les objets de fichier sont nettoyés uniquement lorsque vous manquez de mémoire, pas lorsque vous manquez de poignées de fichier. Donc, si vous faites cela trop souvent, vous pouvez finir de fonctionner par des descripteurs de fichier et que vos tentatives d'ouverture des fichiers d'ouverture des fichiers ont des exceptions.


2 commentaires

Notez que cela lira tout le fichier dans la mémoire, peu importe la taille. Assurez-vous donc que c'est un fichier que vous pouvez gérer. Outre cela, je suis d'accord avec les réponses.


@balpha: Mais les réponses sont contradictoires. ;) (Je suppose que vous avez fait le commentaire avant toutes les réponses.)


6 Réponses :


3
votes

Non, c'est le style Python parfaitement raisonnable OMI, selon votre raisonnement.

Mise à jour: Il y a beaucoup de commentaires ici de savoir si les objets de fichiers se rangèrent loin ou pas droit. Plutôt que de spéculer, je l'ai fait quelques recherches. Voici ce que je vois:


D'un commentaire en Python . h :

Les macros Py_INCREF (op) et Py_DECREF (op) sont utilisés pour augmenter ou décrémentation compte de référence. Py_DECREF appelle la deallocator de l'objet fonction lorsque le refcount tombe à 0

Recherche en Python est fileobject.c :

La table de fonction pour le fichier des objets points fonction file_dealloc . cette fonction appels close_the_file , qui à son tour ferme le fichier.


Il semble donc raisonnable d'affirmer que pour le moment, sur CPython, quand il n'y a pas références à un objet fichier, il est fermé sans délai. Si vous pensez que cette interprétation est erronée, s'il vous plaît poster un commentaire indiquant pourquoi vous vous sentez de cette façon.

5 commentaires

Raisonnable, mais les ressources du système d'exploitation ne peuvent pas être aussi totalement disponibles que vous le souhaitez. Par exemple, essayant de supprimer le fichier immédiatement après la lecture, il peut ne pas fonctionner car les ressources du système d'exploitation sont tenues par des bibliothèques C sous-jacentes, pensaient même que le fichier Python fichier a été recueilli. Jusqu'à ce que le système d'exploitation pense que le fichier n'est plus utilisé, vous ne pourrez peut-être pas la supprimer.


@ S. Lott: Préférez-vous qu'un objet CODE> COLLED-COLLUÉE n'est pas fermé (de sorte que le système d'exploitation sache qu'il n'est plus utilisé)? Je voudrais attendre que la suppression d'un objet de fichier ferme le fichier, mais je ne trouve rien dans la documentation.


Je crois comprendre que CPPHON (la mise en œuvre de la référence que la plupart des gens pensent quand ils pensent Python) détruisent en fait tous les objets non référencés lorsqu'ils laissent la portée. Dans ce cas, l'objet de fichier quitte la portée dès que l'opération de lecture () est terminée. Donc, il devrait faire exactement ce que vous voulez. Ce n'est pas un comportement garanti, cependant. D'autres implémentations de Python (Jython, je pense être un exemple d'excellence) peuvent gérer la collecte des ordures différemment. Mon instinct est d'utiliser la mise en œuvre simple si vous savez que vous utilisez CPPHON et ne vous souciez pas de la portabilité.


La question n'est pas la collection de la poubelle en soi . C'est la relation entre un objet deallocate et toutes les ressources du système d'exploitation. Je soupçonne (mais je ne sais pas) que l'objet est simplement distribué et que le gérant du fichier de système d'exploitation sous-jacent reste suspendu.


@Jason, c'est faux. Je crois comprendre que la collecte des ordures n'est jamais garantie.



1
votes

a l'air bien pour moi .. je lis des fichiers comme ça souvent.


0 commentaires

7
votes

Il est vrai que cela fermera éventuellement, mais finalement pourrait ne pas être assez bientôt. Surtout si vous utilisez ceci à l'intérieur d'une boucle, le système peut s'exécuter de poignées de fichier avant que le GC ne reçoit les objets de fichier.


3 commentaires

Mais si le fichier FileObj est compté .. Il va à 0 directement et est supprimé immédiatement? En cpython (?).


@ kaizer.se: Ce n'est toujours pas nécessairement immédiatement supprimé. Seulement lorsque CPPHON a besoin de plus de mémoire.


Attends j'avais tort. devrait être supprimé immédiatement car c'est la manière dont les travaux de comptage de référence. Sauf si il y a du cycle dans l'objet de fichier lui-même. Cette réponse est-elle juste fausse? Sinon, alors pourquoi les objets ne sont-ils pas supprimés tout de suite?



30
votes

juste pour le record: Ceci n'est que légèrement plus long et ferme immédiatement le fichier:

from __future__ import with_statement

with open(filename, "r") as f:
    data = f.read()


6 commentaires

+1 J'ai ajouté le Import au cas où ils utilisent Python 2.5 :)


Une question de style suivi: est-ce vraiment affreux de faire avec Open ("T1.py", "r") comme F: F.Read () Tout sur une ligne? Je sais que ce n'est pas aussi lisible, mais si souvent, la lecture du dossier est une sorte de chose très fondamentale et le prochain gars de lecture du code ne se soucie vraiment pas de la façon dont vous l'avez fait.


@Jenn D: Un point du avec est de confiner tout le traitement en une portée bien rangée. Mettre avec ouverte () comme F: F.Read () dans une sorte de ligne de défaite le but de la conformité de avec .


Cela n'a tout simplement pas de sens. Le scopage est identique, qu'il y ait une nouvelle ligne dedans ou non. Je n'aime pas cela comme style, mais la portée n'entre pas.


@Glenn: Ce n'est pas la nouvelle ligne, c'est la suite entièrement en retrait. L'intention de avec est de lire et de traiter les données dans un contexte étroitement lié. Utilisation d'une ligne avec ceci comme celle-ci: variable = ça.Read () est-ce que vous avez maintenant un effet secondaire à partir du bloc avec le bloc, perdez la liaison bien rangée.


Je pense que c'est une question de style. Je pourrais utiliser votre argument remplacer avec avec pour , et j'ai souvent une doublure pour les boucles



4
votes

Le code fonctionne exactement comme vous le dites, mais c'est néanmoins mauvais. Votre code repose sur des hypothèses qui peuvent être vraies maintenant, mais ne seront pas toujours vraies. Il n'est pas impossible que votre code soit exécuté dans une situation où le fichier étant ouvert et ne ferme pas fait matière. Cela vaut-il vraiment la peine d'économiser 1 ou 2 lignes de code? Je ne le pense pas.


0 commentaires

2
votes

Même si cela fonctionne comme prévu, je pense que cela échoue en deux chefs d'accusation:

  1. Votre code n'augmentera pas de manière transparente de manière transparente, car vous lisez tout le fichier en mémoire, ce qui peut ne pas être nécessairement ce que vous voulez.
  2. Selon le zen de Python (Essayez Importer ce dans l'invite Python pour la récupérer) "Explicit est meilleur que implicite" et, en omettant explicitement fermé explicitement le fichier, vous pouvez confondre quelqu'un qui , en bas de la route, sera laissé avec votre code pour la maintenance.

    Cela aide vraiment à être explicite! Python encourage le style explicite.

    Autre que cela, pour un script jetable, votre style a du sens.

    Peut-être que vous bénéficierez de Cette réponse .


0 commentaires