Curso de Python / Ler e gravar CSV com DictReader e DictWriter
CSV, de Comma Separated Values, armazena registros e campos como texto. Use o módulo csv para interpretar delimitadores e aspas e depois valide os dados: os valores lidos por DictReader neste exemplo são strings, inclusive os que representam números.
Interpretar campos com aspas e escolher a abertura do arquivo
Um campo pode conter uma vírgula sem representar uma coluna adicional: basta que o formato use as aspas apropriadas. Campos entre aspas também podem conter quebras de linha. split(",") não interpreta essas regras e pode separar incorretamente o conteúdo de um único campo. Use csv.reader para sequências de campos ou csv.DictReader para associá-los aos nomes do cabeçalho.
Abra os arquivos com newline="" para deixar o módulo csv administrar as quebras de linha. A codificação continua sendo uma escolha separada: utf-8-sig lê UTF-8 e remove uma assinatura BOM inicial quando ela está presente. BOM significa Byte Order Mark, uma marca que algumas ferramentas incluem no início do arquivo; sem o tratamento adequado, ela pode aparecer no primeiro nome de coluna.
CSV tem variações de delimitador, aspas e convenções entre programas. O exemplo usa vírgula como delimitador; um arquivo separado por ponto e vírgula exige configuração correspondente. O módulo resolve a estrutura, mas não decide se campos extras, cabeçalhos duplicados, notas vazias ou valores negativos são aceitáveis.
Gravar um nome com vírgula e calcular o total
Use uma pasta separada e descartável: o programa substitui expenses-demo.csv a cada execução. Salve o código completo em csv_demo.py, com UTF-8, e execute python csv_demo.py no terminal dessa pasta, com o ambiente virtual selecionado se houver. Em macOS ou Ubuntu sem ambiente virtual, use python3 csv_demo.py quando necessário. O módulo csv faz parte da biblioteca padrão.
import csv
from pathlib import Path
path = Path("expenses-demo.csv")
with path.open("w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["name", "amount"])
writer.writeheader()
writer.writerows([{ "name": "lunch, team", "amount": 8000}, {"name": "bus", "amount": 2500}])
total = 0
with path.open(encoding="utf-8-sig", newline="") as f:
reader = csv.DictReader(f)
if reader.fieldnames != ["name", "amount"]:
raise ValueError("unexpected header")
for row in reader:
total += int(row["amount"])
print(row["name"])
print("total:", total)
O resultado esperado é:
lunch, team
bus
total: 10500
DictWriter usa os nomes name e amount para gravar o cabeçalho e os registros. O nome lunch, team, correspondente a um almoço em equipe, contém uma vírgula e é gravado como um campo entre aspas. Ao ler, DictReader recupera esse nome inteiro, sem as aspas que serviam para delimitar o campo.
O leitor exige o cabeçalho exatamente na ordem ["name", "amount"]. Depois, int(row["amount"]) converte cada valor e o adiciona ao acumulador. Os dois valores produzem 10500. A coluna de nomes é exibida separadamente; a vírgula visível no primeiro nome não significa que o registro passou a ter três colunas.
Abra o CSV num editor de texto para observar as aspas e depois leia-o com um leitor CSV para verificar os valores. A simples aparência da saída do terminal não comprova a estrutura dos registros. A prática anterior de abertura de texto, codificação e modos de escrita ajuda a distinguir o conteúdo em disco da forma como ele é apresentado.
Definir validação de números, colunas e posições
O programa trata o arquivo criado por ele próprio. Ele não é um importador completo para qualquer CSV externo: cabeçalhos iguais não garantem que cada registro tenha o número certo de campos. Por padrão, campos excedentes de um DictReader podem aparecer sob a chave None; campos ausentes podem receber o valor None. Para aceitar dados externos, verifique a estrutura de cada registro antes de converter valores.
Uma string vazia, "8,000" ou um valor com símbolo de moeda não é aceito diretamente por int(). Não apague indiscriminadamente caracteres para forçar uma conversão: defina o formato permitido e registre os valores rejeitados. Além disso, converter com sucesso não valida regras de negócio; "-1" é convertido em inteiro negativo, mesmo que a aplicação não devesse aceitá-lo.
Erros de conversão interrompem este programa, pois não há tratamento de rejeitados no laço. Se a falha ocorrer num registro posterior, nomes dos registros anteriores já podem ter sido impressos, mas a linha final de total não será alcançada. Para produzir um relatório parcial confiável, seria necessário definir explicitamente quais erros permitem continuar e como informar as rejeições.
enumerate(reader, start=2) pode identificar registros lógicos após o cabeçalho. Quando um campo contém uma quebra de linha, essa numeração não corresponde às linhas físicas do arquivo. reader.line_num indica o número de linhas físicas já consumidas pelo leitor, e não simplesmente um número de registro. Informe qual posição está sendo usada no diagnóstico.
Verificar releitura, cabeçalho e exportações para planilhas
- Execute o programa e leia novamente o arquivo com
csv.reader. Confirme que cada registro tem dois campos e que o primeiro nome é exatamentelunch, team. Abra o texto bruto e confira que o nome com vírgula está entre aspas. - Para testar somente um cabeçalho inesperado, substitua temporariamente
writer.writeheader()porwriter.writerow({"name": "name", "amount": "cost"}). Isso mantém as chaves usadas na escrita dos dados, mas gravaname,costno cabeçalho. A leitura deve parar comValueError: unexpected header, sem imprimir nomes nem total. - Restaure
writer.writeheader()e execute duas vezes. A saída continua igual e o arquivo contém um cabeçalho e dois registros, porquewsubstitui o conteúdo em cada execução. - Para observar um campo multilinha, troque somente
"lunch, team"por"lunch,\nteam"no registro escrito. O nome continua sendo um campo, embora a impressão ocupe duas linhas e a contagem de linhas físicas aumente. Restaure o texto original para recuperar a saída inicial.
Editar apenas o arquivo CSV e depois executar este programa inteiro não testa uma entrada externa alterada: a parte de escrita recria o arquivo antes da leitura. Para testar arquivos recebidos de fora, separe deliberadamente a rotina de leitura da criação dos dados e mantenha uma cópia dos arquivos de teste.
Ao compartilhar um CSV com uma planilha, considere que a aplicação pode interpretar determinados textos externos, como os que começam por =, como fórmulas. Colocar o campo entre aspas CSV protege a separação dos campos, mas não determina o tratamento da célula pela planilha. Defina uma política de exportação compatível com o programa destinatário. O módulo csv e suas classes de leitura e escrita cuida do formato; a referência de UTF-8 com assinatura explica o tratamento da marca inicial, sem substituir a validação dos valores.




