À l'époque préhistorique (Python 1.4), nous avons fait:
fp = open('filename.txt')
while 1:
line = fp.readline()
if not line:
break
print line
après Python 2.1, nous avons fait:
for line in open('filename.txt').xreadlines():
print line
avant d'avoir le protocole d'itérateur pratique dans Python 2.3, et pourrions faire:
for line in open('filename.txt'):
print line
J'ai vu quelques exemples utilisant les plus verbeux:
with open('filename.txt') as fp:
for line in fp:
print line
est-ce la méthode préférée pour l'avenir?
[modifier] J'obtiens que l'instruction with assure la fermeture du fichier ... mais pourquoi n'est-ce pas inclus dans le protocole d'itérateur pour les objets fichier?
python
python-3.x
python-2.7
thebjorn
la source
la source
Réponses:
Il y a exactement une raison pour laquelle ce qui suit est préféré:
Nous sommes tous gâtés par le schéma de comptage de références relativement déterministe de CPython pour le garbage collection. D'autres implémentations hypothétiques de Python ne fermeront pas nécessairement le fichier "assez rapidement" sans le
with
bloc si elles utilisent un autre schéma pour récupérer la mémoire.Dans une telle implémentation, vous pouvez obtenir une erreur "trop de fichiers ouverts" du système d'exploitation si votre code ouvre les fichiers plus rapidement que le garbage collector appelle les finaliseurs sur les descripteurs de fichiers orphelins. La solution habituelle de contournement consiste à déclencher le GC immédiatement, mais c'est un mauvais hack et cela doit être fait par chaque fonction qui pourrait rencontrer l'erreur, y compris celles des bibliothèques. Quel cauchemard.
Ou vous pouvez simplement utiliser le
with
bloc.Question bonus
(Arrêtez de lire maintenant si vous n'êtes intéressé que par les aspects objectifs de la question.)
C'est une question subjective sur la conception d'API, j'ai donc une réponse subjective en deux parties.
Au niveau de l'intestin, cela semble faux, car cela oblige le protocole de l'itérateur à faire deux choses distinctes - itérer sur les lignes et fermer le descripteur de fichier - et c'est souvent une mauvaise idée de faire faire deux actions à une fonction simple. Dans ce cas, cela se sent particulièrement mal car les itérateurs sont liés de manière quasi fonctionnelle et basée sur la valeur au contenu d'un fichier, mais la gestion des descripteurs de fichiers est une tâche complètement distincte. Ecraser les deux, de manière invisible, en une seule action est surprenant pour les humains qui lisent le code et rend plus difficile le raisonnement sur le comportement du programme.
D'autres langues sont essentiellement parvenues à la même conclusion. Haskell a brièvement flirté avec le soi-disant «paresseux IO» qui vous permet d'itérer sur un fichier et de le fermer automatiquement lorsque vous arrivez à la fin du flux, mais il est presque universellement découragé d'utiliser des IO paresseux dans Haskell ces jours-ci, et Haskell les utilisateurs sont généralement passés à une gestion des ressources plus explicite comme Conduit qui se comporte plus comme le
with
bloc en Python.Sur le plan technique, il y a certaines choses que vous voudrez peut-être faire avec un descripteur de fichier en Python qui ne fonctionneraient pas aussi bien si l'itération fermait le descripteur de fichier. Par exemple, supposons que je doive parcourir le fichier deux fois:
Bien que ce soit un cas d'utilisation moins courant, considérez le fait que j'aurais pu simplement ajouter les trois lignes de code en bas à une base de code existante qui avait à l'origine les trois lignes supérieures. Si l'itération fermait le fichier, je ne pourrais pas le faire. Ainsi, séparer les itérations et la gestion des ressources permet de composer plus facilement des morceaux de code dans un programme Python plus volumineux et fonctionnel.
La composabilité est l'une des fonctionnalités d'utilisabilité les plus importantes d'un langage ou d'une API.
la source
with
vous donne la tranquillité d'esprit, c'est donc toujours une bonne pratique.Oui,
est la voie à suivre.
Ce n'est pas plus verbeux. C'est plus sûr.
la source
si vous êtes désactivé par la ligne supplémentaire, vous pouvez utiliser une fonction wrapper comme ceci:
dans Python 3.3, l'
yield from
instruction rendrait cela encore plus court:la source
la source