Использование инструкции “with” для CSV-файлов в Python
-
22-07-2019 - |
Вопрос
Можно ли использовать with
выписка непосредственно из CSV-файлов?Кажется естественным иметь возможность делать что-то подобное:
import csv
with csv.reader(open("myfile.csv")) as reader:
# do things with reader
Но csv.reader не предоставляет __enter__
и __exit__
методы, так что это не работает.Однако я могу сделать это в два этапа:
import csv
with open("myfile.csv") as f:
reader = csv.reader(f)
# do things with reader
Является ли этот второй способ идеальным способом сделать это?Почему бы им не сделать csv.reader напрямую совместимым с оператором with?
Решение
Основное использование оператора with
- это безопасная для исключения очистка объекта, используемого в операторе. с
гарантирует, что файлы закрыты, блокировки сняты, контексты восстановлены и т. д.
Есть ли у csv.reader какие-либо вещи для очистки в случае исключение?
Я бы пошел с:
with open("myfile.csv") as f:
for row in csv.reader(f):
# process row
Вам не нужно отправлять патч для совместного использования csv.reader
и с оператором
.
import contextlib
Справка по функции contextmanager в модуле contextlib :
contextmanager(func)
@contextmanager decorator.
Типичное использование:
@contextmanager
def some_generator(<arguments>):
<setup>
try:
yield <value>
finally:
<cleanup>
Это делает это
with some_generator(<arguments>) as <variable>:
<body>
эквивалентно этому:
<setup>
try:
<variable> = <value>
<body>
finally:
<cleanup>
Другие советы
ДА.Второй способ является правильным.
Что касается того, почему?Кто бы мог подумать.Вы правы, вероятно, это простое изменение.Это не такой высокий приоритет, как другие вещи.
Вы можете легко создать свой собственный набор исправлений и отправить его.
Проблема в том, что csv.reader не управляет контекстом. Может принимать любой итеративный, а не только файл. Поэтому он не вызывает close на своем входе (кстати, если бы он это сделал, вы могли бы использовать contextlib.closing). Так что не совсем понятно, что в действительности делает контекстная поддержка csv.reader.
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
Легко создать то, что вы хотите, используя функцию генератора:
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