Utilisation de & # 8220; avec & # 8221; instruction pour les fichiers CSV en Python
-
22-07-2019 - |
Question
Est-il possible d'utiliser l'instruction avec
directement avec des fichiers CSV? Il semble naturel de pouvoir faire quelque chose comme ceci:
import csv
with csv.reader(open("myfile.csv")) as reader:
# do things with reader
Mais csv.reader ne fournit pas les méthodes __ enter __
et __ exit __
, donc cela ne fonctionne pas. Je peux cependant le faire en deux étapes:
import csv
with open("myfile.csv") as f:
reader = csv.reader(f)
# do things with reader
Est-ce que cette deuxième façon est la manière idéale de le faire? Pourquoi ne rendraient-ils pas csv.reader directement compatible avec l'instruction with?
La solution
L'utilisation principale de avec l'instruction
est un nettoyage protégé contre les exceptions d'un objet utilisé dans l'instruction. avec
permet de s'assurer que les fichiers sont fermés, que les verrous sont libérés, que les contextes sont restaurés, etc.
csv.reader a-t-il des choses à nettoyer en cas de exception?
J'irais avec:
with open("myfile.csv") as f:
for row in csv.reader(f):
# process row
Il n'est pas nécessaire de soumettre le correctif pour utiliser simultanément csv.reader
et avec
.
import contextlib
Aide sur la fonction contextmanager dans le module contextlib :
contextmanager(func)
@contextmanager decorator.
Utilisation typique:
@contextmanager
def some_generator(<arguments>):
<setup>
try:
yield <value>
finally:
<cleanup>
Cela fait ceci:
with some_generator(<arguments>) as <variable>:
<body>
équivalent à ceci:
<setup>
try:
<variable> = <value>
<body>
finally:
<cleanup>
Voici un exemple concret d'utilisation de ce logiciel: curses_screen .
Autres conseils
Oui. La deuxième façon est correcte.
Quant à pourquoi? Qui sait jamais. Vous avez raison, c'est probablement un changement facile. Ce n’est pas aussi prioritaire que d’autres choses.
Vous pouvez facilement créer votre propre kit de correctifs et le soumettre.
Le problème est que csv.reader ne gère pas vraiment un contexte. Il peut accepter tout type de données, pas seulement un fichier. Par conséquent, il n'appelle pas close sur son entrée (d'ailleurs, si c'était le cas, vous pourriez utiliser contextlib.closing). Il n’est donc pas évident de savoir quel support de contexte pour csv.reader ferait réellement.
import csv
class CSV(object):
def __init__(self,path,mode):
self.path = path
self.mode = mode
self.file = None
def __enter__(self):
self.file = open(self.path,self.mode)
if self.mode == 'r':
return csv.reader(self.file)
elif self.mode == 'w':
return csv.writer(self.file)
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
with CSV('data.csv','r') as reader:
for row in reader:
print row
Il est facile de créer ce que vous voulez en utilisant une fonction de générateur:
import csv
from contextlib import contextmanager
@contextmanager
def opencsv(path):
yield csv.reader(open(path))
with opencsv("myfile.csv") as reader:
# do stuff with your csvreader