Usando a declaração "com" para arquivos CSV no Python
-
22-07-2019 - |
Pergunta
É possível usar o with
Declaração diretamente com arquivos CSV? Parece natural poder fazer algo assim:
import csv
with csv.reader(open("myfile.csv")) as reader:
# do things with reader
Mas o CSV.Reader não fornece o __enter__
e __exit__
Métodos, então isso não funciona. No entanto, posso fazer isso em duas etapas:
import csv
with open("myfile.csv") as f:
reader = csv.reader(f)
# do things with reader
Esta é a segunda maneira da maneira ideal de fazer isso? Por que eles não tornariam o CSV. Reader diretamente compatível com a declaração com com?
Solução
O uso primário de with
A declaração é uma limpeza segura por exceção de um objeto usado na instrução. with
Garanta que os arquivos estejam fechados, os bloqueios sejam liberados, os contextos são restaurados, etc.
Faz CSV.Reader Tem coisas para limpar em caso de exceção?
Eu iria com:
with open("myfile.csv") as f:
for row in csv.reader(f):
# process row
Você não precisa enviar o patch para usar csv.reader
e with
declaração juntos.
import contextlib
Ajuda na função contextManager no módulo contextlib:
contextmanager(func)
@contextmanager decorator.
Uso típico:
@contextmanager
def some_generator(<arguments>):
<setup>
try:
yield <value>
finally:
<cleanup>
Isso faz disso:
with some_generator(<arguments>) as <variable>:
<body>
equivalente a isso:
<setup>
try:
<variable> = <value>
<body>
finally:
<cleanup>
Aqui está um exemplo concreto de como eu o usei: Curses_screen.
Outras dicas
Sim. A segunda maneira está correta.
Quanto a por quê? Quem já sabe. Você está certo, provavelmente é uma mudança fácil. Não é tão alta prioridade quanto outras coisas.
Você pode facilmente criar seu próprio kit de patch e enviá -lo.
O problema é que o CSV. Reader realmente não gerencia um contexto. Pode aceitar qualquer iterável, não apenas um arquivo. Portanto, ele não liga para fechar sua entrada (aliás, se o fizesse, você poderia usar o contextlib.closing). Portanto, não é óbvio qual suporte de contexto para o CSV. Reader realmente faria.
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
É fácil criar o que você deseja usando uma função de gerador:
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