Menu
Русский

CSV в Python: чтение и запись CSV-файлов модулем csv

Как читать и писать CSV в Python — модуль csv, DictReader и DictWriter, заголовки, кавычки и когда стоит переключиться на pandas.

CSV проще, чем кажется (и хитрее, чем ожидаешь)

CSV-файл — это просто текст: строки разделены переводами строк, поля — запятыми. Таков замысел. На практике натыкаешься на строки в кавычках с запятыми внутри, поля со встроенными переводами, разные региональные соглашения (запятая или точка с запятой), файлы из Excel с BOM — краевых случаев достаточно, чтобы писать свой line.split(",") почти всегда было ошибкой.

Модуль csv стандартной библиотеки обрабатывает всё это. Для маленьких и средних файлов тебе редко понадобится что-то ещё.

Чтение CSV через csv.reader

csv.reader выдаёт каждую строку списком строк:

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

Пара неочевидных деталей:

  • Всегда передавай newline="" в open. Модуль csv сам следит за переводами строк; без этого на Windows появятся лишние пустые ряды.
  • Каждое значение — строка. "42" останется строкой, пока не вызовешь int(...). У CSV нет типов.
  • Строка заголовка — такая же строка, как остальные. Если заголовки есть — либо вручную пропусти первую, либо переключайся на DictReader.

Пропускаем заголовок

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    headers = next(reader)         # pulls the first row out
    for row in reader:
        print(row)

next(reader) сдвигает итератор на один и возвращает ту строку.

Чтение как словарей через DictReader

csv.DictReader воспринимает первую строку как заголовки и отдаёт каждую следующую словарём:

import csv

with open("people.csv", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["email"])

Это почти всегда то, что нужно. Имена колонок самодокументируются, и перестановка колонок в исходнике не ломает код.

Если заголовков нет — передай их явно: fieldnames=["name", "email", ...].

Запись CSV через csv.writer

csv.writer превращает ряды (списки) в строки CSV:

import csv

rows = [
    ["name", "age", "city"],
    ["Rosa", 30, "Lisbon"],
    ["Ada", 36, "London"],
]

with open("out.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(rows)

writerow(row) пишет один ряд; writerows(rows) — всё итерируемое сразу. Оба автоматически оборачивают поля в кавычки, когда внутри запятые, кавычки или переводы строк, — об этом думать не надо.

Запись словарей через DictWriter

Когда данные уже в виде словарей, DictWriter пропускает шаг «превратить в список»:

import csv

people = [
    {"name": "Rosa", "age": 30, "city": "Lisbon"},
    {"name": "Ada", "age": 36, "city": "London"},
]

with open("out.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "age", "city"])
    writer.writeheader()
    writer.writerows(people)

Аргумент fieldnames управляет и заголовком, и порядком колонок. Ключи словарей, не попавшие в fieldnames, молча выкидываются (или можно ругаться через extrasaction="raise").

Разные разделители и кавычки

Не в каждом «CSV» запятые. В европейских локалях часто ;, tab-separated файлы используют \t, в некоторых системах — |. Передай аргумент delimiter=:

import csv

with open("data.tsv", newline="") as f:
    reader = csv.reader(f, delimiter="\t")
    for row in reader:
        print(row)

Для файлов с необычными правилами цитирования csv.register_dialect(...) позволяет один раз настроить и переиспользовать. Для большинства файлов хватает дефолтов плюс delimiter=.

Кодировка

CSV — это текст, у него есть кодировка. UTF-8 — современный дефолт; файлы из Excel на Windows иногда в cp1252 или с UTF-8 BOM. Будь явным:

with open("data.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    ...

Видишь UnicodeDecodeError — файл не в той кодировке, что ты угадал. Обычные подозреваемые: utf-8-sig (учитывает Excel-овский BOM), cp1252, latin-1.

Превращаем строки CSV в полезные типы

Поскольку каждое значение приходит строкой, парсинг на тебе:

main.py
Output
Click Run to see the output here.

(StringIO позволяет запустить пример без реального файла — в настоящем коде ты бы сделал open(path).)

Для CSV со сложными типами (даты, nullable-числа, true/false в десяти разных написаниях) — подумай о pandas: у него конвенции встроены.

Когда тянуться к pandas

pandas.read_csv(path) возвращает DataFrame — правильную структуру с того момента, когда хочется:

  • фильтровать ряды: df[df["active"] == True]
  • агрегировать: df.groupby("city")["age"].mean()
  • джойнить с другой таблицей
  • записывать обратно с простым форматированием
import pandas as pd

df = pd.read_csv("people.csv")
adults = df[df["age"] >= 18]
adults.to_csv("adults.csv", index=False)

Для маленьких линейных чтений pandas — перебор, и это тяжёлая зависимость (поставь pip-ом в виртуальное окружение). Но для всего «в форме данных» — это инструмент, к которому большинство Python-аналитиков тянется.

Стриминг очень больших файлов

csv.reader уже ленив — читает ряд за раз. Оставляй его таким: итерируй (а не делай list(reader) заранее), и память остаётся плоской независимо от размера:

import csv

with open("huge.csv", newline="") as f:
    reader = csv.DictReader(f)
    error_count = 0
    for row in reader:
        if row["status"] == "error":
            error_count += 1

print(f"Found {error_count} errors.")

Так спокойно тянется и 10 ГБ, и 10 КБ — лишь бы ты не копил ряды в список.

Несколько привычек

  • Всегда передавай newline="" в open при чтении и записи CSV.
  • Используй DictReader/DictWriter, когда у файла есть заголовки — читается лучше, чем индексы.
  • Будь явным с кодировкой, особенно для файлов из Excel или неанглоязычных источников.
  • Конвертируй типы прямо на этапе чтения, чтобы код ниже уже имел дело с нормальными значениями.
  • Тянись к pandas, когда хочешь анализировать данные, а не просто двигать их.

Дальше

Теперь ты умеешь читать JSON и CSV. Последний реальный навык, который мы разберём, — тянуть данные по сети, и это следующая страница про HTTP-запросы через библиотеку requests.

Часто задаваемые вопросы

Как прочитать CSV-файл в Python?

Используй встроенный модуль csv. csv.reader даёт каждую строку списком строк; csv.DictReader использует первую строку как заголовки и выдаёт каждую следующую словарём. Открой файл с newline='', чтобы Python не калечил переводы строк: with open('data.csv', newline='') as f:.

Как записать CSV-файл в Python?

Сочетай csv.writer с файлом, открытым на запись с newline=''. Вызывай writer.writerow([...]) для одной строки или writer.writerows([[...], [...]]) для пачки. Для словарей — csv.DictWriter, он автоматически обрабатывает заголовки.

Модуль csv или pandas?

csv — для быстрого чтения и записи, обработки построчно и когда не хочется лишних зависимостей. pandas — когда нужно фильтровать, группировать или джойнить, либо файл настолько большой, что важна векторизация. Файлы они обрабатывают одни и те же; выбор — про то, что ты делаешь с данными после загрузки.

Почему у моего CSV на Windows пустые строки между рядами?

Ты открыл файл без newline=''. Модуль csv сам пишет терминаторы строк; без этого аргумента Python на Windows добавляет лишние. Всегда открывай CSV через open(path, newline='') и на чтение, и на запись.

Учитесь программировать с Coddy

НАЧАТЬ