Leer y escribir CSV en Python

Python trae un módulo csv que resuelve las partes difíciles del formato: las comillas dentro de los campos, los separadores dentro de los valores y los saltos de línea. Usarlo cuesta lo mismo que no usarlo.

Escribir

import csv
from pathlib import Path

p = Path("datos.csv")
with p.open("w", encoding="utf-8", newline="") as f:
    w = csv.DictWriter(f, fieldnames=["nombre", "ciudad", "precio"], delimiter=";")
    w.writeheader()
    w.writerows(filas)
datos.csvnombre;ciudad;precio
"bufanda ""larga""";A Coruña;9.00
"mochila; grande";Madrid;34.00

Mira lo que hizo solo: entrecomilló los dos campos que lo necesitaban y duplicó las comillas de dentro. Eso es el formato CSV bien hecho, y es lo que te ahorras escribir.

El newline="" no es opcional. El módulo csv gestiona él mismo los finales de línea; sin ese argumento, en Windows salen líneas en blanco entre registro y registro. Hay que ponerlo siempre, al abrir tanto para leer como para escribir.

Leer

with p.open(encoding="utf-8", newline="") as f:
    for fila in csv.DictReader(f, delimiter=";"):
        print(fila["nombre"], fila["ciudad"], float(fila["precio"]))
salidabufanda "larga"    A Coruña       9.00
mochila; grande    Madrid        34.00

Volvieron enteros, con las comillas deshechas y el punto y coma de «mochila; grande» intacto. DictReader usa la primera fila como nombres de columna, lo que se lee mucho mejor que fila[2] y aguanta que cambien de orden.

Y ojo con una cosa: todo llega como cadena. El float() lo pones tú; el módulo no adivina tipos.

Por qué nunca split

linea = '"mochila; grande";Madrid;34.00'
salidasplit(';')  -> ['"mochila', ' grande"', 'Madrid', '34.00']
csv.reader  -> ['mochila; grande', 'Madrid', '34.00']

Cuatro campos en vez de tres, y todas las columnas desplazadas a partir de ahí. Si el archivo viene de fuera, antes o después hay un campo con el separador dentro.

Cuando no sabes el separador

d = csv.Sniffer().sniff(muestra, delimiters=",;\t")
csv.Sniffer().has_header(muestra)
salidaSniffer dice: ';'   ¿hay cabecera? True

Útil para archivos ajenos, donde nunca sabes si vienen con coma, con punto y coma —lo habitual en España, porque la coma es el decimal— o con tabulador. No es infalible: dale varios cientos de bytes de muestra, no una línea.

Saltos de línea dentro de un campo

salidaescrito: 'nota;"línea 1\nlínea 2"\r\n'
leído  : ['nota', 'línea 1\nlínea 2']

Esto es lo que rompe a los analizadores caseros, incluidos los que leen línea a línea: un registro puede ocupar varias líneas del archivo. El módulo csv lo lleva bien, y por eso hay que iterar el lector y no el archivo.

Para… Usa
Leer con nombres de columna csv.DictReader
Escribir desde diccionarios csv.DictWriter + writeheader()
Listas en vez de diccionarios csv.reader / csv.writer
Separador europeo delimiter=";"
Adivinar el formato csv.Sniffer()
Evitar líneas en blanco newline="" al abrir
Archivos enormes o cálculo pandas o polars, no csv

Todo el código se ejecutó con Python 3.14 en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.