Pregunta

¿Es posible usar la instrucción with directamente con archivos CSV? Parece natural poder hacer algo como esto:

import csv
with csv.reader(open("myfile.csv")) as reader:
    # do things with reader

Pero csv.reader no proporciona los métodos __enter__ y __exit__ , por lo que esto no funciona. Sin embargo, puedo hacerlo en dos pasos:

import csv
with open("myfile.csv") as f:
    reader = csv.reader(f)
    # do things with reader

¿Es esta segunda forma la forma ideal de hacerlo? ¿Por qué no harían csv.reader directamente compatible con la declaración with?

¿Fue útil?

Solución

El uso principal de la instrucción with es una limpieza segura de excepciones de un objeto utilizado en la declaración. with se asegura de que los archivos estén cerrados, se liberen bloqueos, se restauren los contextos, etc.

¿ csv.reader tiene cosas que limpiar en caso de excepción?

Yo iría con:

with open("myfile.csv") as f:
    for row in csv.reader(f):
        # process row

No necesita enviar el parche para usar csv.reader y con declaración juntos.

import contextlib

Ayuda sobre la función contextmanager en el módulo contextlib :

contextmanager(func)
    @contextmanager decorator.

Uso típico:

    @contextmanager
    def some_generator(<arguments>):
        <setup>
        try:
            yield <value>
        finally:
            <cleanup>

Esto hace que:

    with some_generator(<arguments>) as <variable>:
        <body>

equivalente a esto:

    <setup>
    try:
        <variable> = <value>
        <body>
    finally:
        <cleanup>

Aquí hay un ejemplo concreto de cómo lo he usado: curses_screen .

Otros consejos

Sí La segunda forma es correcta.

¿Por qué? Quien sabe Tienes razón, probablemente sea un cambio fácil. No es tan prioritario como otras cosas.

Puede hacer fácilmente su propio kit de parches y enviarlo.

El problema es que csv.reader no gestiona realmente un contexto. Puede aceptar cualquier iterable, no solo un archivo. Por lo tanto, no llama a close en su entrada (por cierto, si lo hiciera, podría usar contextlib.closing). Por lo tanto, no es obvio qué soporte contextual para csv.reader realmente haría.

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

Es fácil crear lo que quiere usando una función de generador:


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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top