Использование инструкции "с" для файлов CSV в Python
Можно ли использовать оператор 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?
Ответы
Ответ 1
Основное использование оператора with
- это безопасная для исключения очистка объекта, используемого в инструкции. with
гарантирует, что файлы будут закрыты, блокировки будут выпущены, контексты будут восстановлены и т.д.
Есть ли csv.reader что-то делать в случае исключения?
Я бы пошел с:
with open("myfile.csv") as f:
for row in csv.reader(f):
# process row
Вам не нужно отправлять патч для использования инструкций csv.reader
и with
.
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>
Вот конкретный пример того, как я его использовал: curses_screen.
Ответ 2
Да. Второй способ правильный.
В чем причина? Кто знает. Вы правы, это, вероятно, легкое изменение. Это не такой высокий приоритет, как другие вещи.
Вы можете легко создать свой собственный набор патчей и отправить его.
Ответ 3
Проблема заключается в том, что csv.reader действительно не управляет контекстом. Он может принимать любой итеративный, а не только файл. Поэтому он не вызывает близко к своему входу (кстати, если бы вы могли использовать contextlib.closing). Таким образом, неясно, какая контекстная поддержка csv.reader действительно будет делать.
Ответ 4
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
Ответ 5
Легко создать то, что вы хотите, используя функцию генератора:
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