CSV файл в Python: запись, чтение и словари
CSV файл в Python читают и записывают встроенным модулем csv: он сам расставляет разделители и кавычки и превращает строки таблицы в списки или словари. В статье разобраны writer и reader, DictWriter и DictReader, дозапись в существующий файл, разделитель точка с запятой и кодировка, с которой таблица корректно открывается в Excel.

Содержание статьи
Как устроен формат CSV
CSV (Comma-Separated Values) - обычный текстовый файл, где каждая строка является записью таблицы, а значения внутри строки разделены запятой. Первая строка часто содержит названия столбцов. Такой файл открывается в любом редакторе, в Excel, LibreOffice и загружается в базы данных.
name,age,city
Kevin,28,Москва
Alice,23,"Ростов-на-Дону, центр"
Joe,34,"Кафе ""Ромашка"""Если значение содержит запятую, перевод строки или кавычку, его заключают в двойные кавычки, а кавычки внутри удваивают. Из-за этих правил разбирать CSV через line.split(",") ненадежно: третья строка примера распадется на лишние столбцы. Модуль csv учитывает экранирование автоматически.
Модуль входит в стандартную библиотеку. Файл открывается обычной функцией open(), о режимах которой подробно рассказано в статье про чтение и запись файлов. Для CSV есть два обязательных правила: передавать newline="" и явно указывать кодировку.
Запись списков через csv.writer
Функция csv.writer(file) возвращает объект, у которого два метода: writerow() записывает одну строку из списка, writerows() принимает список строк, то есть двумерный список. Числа и другие типы перед записью превращаются в строки.
import csv
friends = [
["name", "age"],
["Kevin", 28],
["Alice", 23],
["Joe", 34],
]
with open("friends.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerows(friends)Параметр newline="" нужен потому, что writer сам завершает строки символами \r\n. Без него на Windows файл получит лишнюю пустую строку после каждой записи.
Чтобы добавить запись в конец существующего файла, откройте его в режиме "a". Режим "w" стирает содержимое при открытии, это частая причина потерянных данных.
with open("friends.csv", "a", newline="", encoding="utf-8") as file:
csv.writer(file).writerow(["Tima", 31])Содержимое файла после двух запусков:
name,age
Kevin,28
Alice,23
Joe,34
Tima,31Чтение через csv.reader
Объект csv.reader(file) перебирается циклом for и на каждом шаге отдает строку файла в виде списка строк. Строку заголовков удобно пропустить вызовом next(reader) до начала цикла.
import csv
with open("friends.csv", newline="", encoding="utf-8") as file:
reader = csv.reader(file)
header = next(reader) # ['name', 'age']
for name, age in reader:
print(name, "-", int(age))
# Kevin - 28
# Alice - 23
# Joe - 34
# Tima - 31Все значения читаются как str, даже если в файле записаны числа. Поэтому возраст в примере приводится к int вручную. Если строка в файле пустая, reader вернет пустой список, и распаковка в две переменные упадет с ValueError, такие строки стоит пропускать проверкой if not row: continue.
Reader читает файл построчно и не загружает его в память целиком, так что подходит и для таблиц на миллионы строк. Если нужен весь файл сразу, используйте rows = list(reader).
Словари: DictWriter и DictReader
Обращаться к столбцам по номеру неудобно: при добавлении нового столбца индексы сдвигаются. Классы DictWriter и DictReader работают со словарями, где ключами служат названия столбцов.
import csv
users = [
{"name": "Tom", "age": 28},
{"name": "Alice", "age": 23},
]
with open("users.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=["name", "age"])
writer.writeheader()
writer.writerows(users)
writer.writerow({"name": "Sam", "age": 41})Параметр fieldnames обязателен и задает порядок столбцов. Метод writeheader() записывает строку заголовков. Если в словаре есть ключ, которого нет в fieldnames, будет ValueError. Лишние ключи можно отбросить параметром extrasaction="ignore", а для отсутствующих ключей задать значение по умолчанию через restval.
with open("users.csv", newline="", encoding="utf-8") as file:
for row in csv.DictReader(file):
print(row["name"], row["age"])
# Tom 28
# Alice 23
# Sam 41DictReader берет названия столбцов из первой строки файла. Если заголовков в файле нет, передайте их сами: csv.DictReader(file, fieldnames=["name", "age"]). Список словарей легко сохранить и в другие форматы, например в JSON.
Разделитель, кавычки и кодировка для Excel
Русская версия Excel по умолчанию ждет в CSV точку с запятой, потому что запятая там служит десятичным разделителем. Файл с запятыми он откроет одной колонкой. Разделитель задается параметром delimiter и у writer, и у reader.
import csv
rows = [["товар", "цена"], ["чай", "120,50"], ["сыр", "480,00"]]
with open("price.csv", "w", newline="", encoding="utf-8-sig") as file:
csv.writer(file, delimiter=";").writerows(rows)Кодировка utf-8-sig добавляет в начало файла метку BOM, по которой Excel понимает, что текст в UTF-8, и показывает кириллицу без кракозябр. Файлы, сохраненные из старого Excel, часто приходят в cp1251, их нужно открывать именно с этой кодировкой, иначе будет UnicodeDecodeError.
| Параметр | По умолчанию | Назначение |
|---|---|---|
delimiter | "," | Символ-разделитель полей |
quotechar | '"' | Символ для кавычек |
quoting | csv.QUOTE_MINIMAL | Когда брать значения в кавычки |
lineterminator | "\r\n" | Конец строки при записи |
skipinitialspace | False | Игнорировать пробел после разделителя |
Если разделитель заранее неизвестен, его можно определить классом csv.Sniffer: метод sniff() анализирует фрагмент текста и возвращает подходящий диалект. Полное описание параметров есть в документации модуля csv.
Когда лучше взять pandas
Модуль csv хорош для построчной обработки, конвертации и простых отчетов без внешних зависимостей. Когда нужно фильтровать, группировать, считать суммы по столбцам или объединять несколько таблиц, удобнее библиотека Pandas: pd.read_csv() загружает файл в DataFrame и сам определяет типы столбцов.
| Критерий | Модуль csv | pandas |
|---|---|---|
| Установка | Не нужна | pip install pandas |
| Типы данных | Все строки | Числа и даты распознаются |
| Память | Построчно, мало | Вся таблица в памяти |
| Анализ | Вручную в цикле | Готовые методы |
Частые вопросы
Короткие ответы на типичные проблемы при работе с CSV.
Почему в CSV появляются пустые строки между записями?
Файл открыт без newline="". На Windows текстовый режим заменяет \n на \r\n, и вместе с \r\n от writer получается лишний перевод строки. Добавьте newline="" в вызов open().
Как прочитать только один столбец?
С DictReader достаточно генератора: names = [row["name"] for row in csv.DictReader(file)]. С обычным reader берут элемент по индексу, предварительно пропустив заголовок.
Как записать в CSV числа с запятой в дробной части?
Модуль csv пишет float с точкой, как str(3.5). Для русского Excel преобразуйте число в строку с заменой: str(price).replace(".", ","), а разделителем полей сделайте точку с запятой.
Можно ли изменить строку прямо в CSV файле?
Нет, текстовый файл нельзя править по месту. Прочитайте все строки в список, измените нужные и перезапишите файл целиком в режиме "w".