Domanda

È possibile utilizzare l'istruzione con direttamente con i file CSV? Sembra naturale poter fare qualcosa del genere:

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

Ma csv.reader non fornisce i metodi __enter__ e __exit__ , quindi non funziona. Posso tuttavia farlo in due passaggi:

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

Questo secondo modo è il modo ideale per farlo? Perché non dovrebbero rendere csv.reader direttamente compatibile con la dichiarazione with?

È stato utile?

Soluzione

L'uso principale dell'istruzione con è una pulizia sicura delle eccezioni di un oggetto utilizzato nell'istruzione. con si assicura che i file vengano chiusi, i blocchi vengano rilasciati, i contesti ripristinati, ecc.

csv.reader ha cose da pulire in caso di eccezione?

Vorrei andare con:

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

Non è necessario inviare la patch per utilizzare csv.reader e con insieme.

import contextlib

Aiuto sul gestore delle funzioni nel modulo contextlib :

contextmanager(func)
    @contextmanager decorator.

Utilizzo tipico:

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

Questo rende questo:

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

equivalente a questo:

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

Ecco un esempio concreto di come l'ho usato: curses_screen .

Altri suggerimenti

Sì. Il secondo modo è corretto.

Quanto al perché? Chi lo sa mai. Hai ragione, probabilmente è un cambiamento facile. Non è la massima priorità di altre cose.

Puoi facilmente creare il tuo kit di patch e inviarlo.

Il problema è che csv.reader non gestisce realmente un contesto. Può accettare qualsiasi iterabile, non solo un file. Pertanto, non chiama close sul suo input (per inciso, se fosse possibile, potresti usare contextlib.closing). Quindi non è ovvio quale supporto contestuale per csv.reader farebbe effettivamente.

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

È facile creare ciò che desideri utilizzando una funzione di generatore:


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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top