Подтвердить что ты не робот

Использование инструкции "с" для файлов 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?

4b9b3361

Ответ 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