Использование инструкции “with” для CSV-файлов в Python

StackOverflow https://stackoverflow.com/questions/441130

  •  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
scroll top