W3docs

CSV-файлы в Python

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

CSV (Comma-Separated Values, значения через запятую) — один из самых распространённых форматов обмена табличными данными: его умеют читать и записывать любые приложения для работы с электронными таблицами, базы данных и инструменты для работы с данными. Встроенный модуль Python csv берёт на себя сложные детали: экранирование полей с запятыми, обработку переносов строк в разных операционных системах и преобразование строк в словари. Устанавливать ничего не нужно — csv входит в стандартную библиотеку Python.

В этой главе рассматриваются чтение CSV-файлов, запись CSV-файлов, работа с DictReader и DictWriter, использование нестандартных разделителей и распространённые ошибки, которых стоит избегать.

Что такое CSV-файл?

CSV-файл — это обычный текстовый файл, в котором каждая строка представляет одну строку данных, а каждое поле внутри строки отделяется разделителем — обычно запятой. Вот минимальный пример:

name,age,city
Alice,30,New York
Bob,25,London

Первая строка, как правило, является заголовком, задающим имена столбцов. Последующие строки содержат фактические данные. Если значение поля само содержит запятую, поле заключается в двойные кавычки:

name,bio
Alice,"Engineer, New York"

Модуль csv обрабатывает такое экранирование прозрачно, избавляя вас от необходимости разбирать это вручную.

Чтение CSV-файлов с помощью csv.reader

csv.reader превращает открытый файл (или любой итерируемый объект строк) в итератор, который возвращает каждую строку в виде списка Python.

Базовый шаблон — чтение CSV-файла строка за строкой

import csv

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

Аргумент newline="" важен. Без него универсальный перевод строк Python может вставить лишние пустые строки на Windows, поскольку модуль csv сам управляет переносами строк внутри.

Если people.csv содержит приведённые выше данные, вывод будет таким:

['name', 'age', 'city']
['Alice', '30', 'New York']
['Bob', '25', 'London']

Обратите внимание: все значения — включая число 30 — возвращаются как строки. Модуль csv не определяет типы данных; преобразовывайте их самостоятельно по мере необходимости.

Пропуск строки заголовка

Если вам нужны только строки с данными, а не заголовок, вызовите next() на объекте reader один раз, чтобы потребить первую строку:

Пропуск заголовка с помощью next()

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    header = next(reader)          # consume and store the header
    print("Columns:", header)
    for row in reader:             # only data rows remain
        name, age, city = row
        print(f"{name} is {age} years old and lives in {city}.")

Вывод:

Columns: ['name', 'age', 'city']
Alice is 30 years old and lives in New York.
Bob is 25 years old and lives in London.

Загрузка всех строк в список

Если вам нужно загрузить весь файл в память за один раз, передайте reader в list():

import csv

with open("people.csv", newline="") as f:
    reader = csv.reader(f)
    rows = list(reader)

print(rows[0])   # header row
print(rows[1])   # first data row

Вывод:

['name', 'age', 'city']
['Alice', '30', 'New York']

Запись CSV-файлов с помощью csv.writer

csv.writer записывает строки в любой файлоподобный объект, автоматически экранируя поля, содержащие разделитель, двойные кавычки или символы переноса строки.

Запись строк в новый CSV-файл

import csv

rows = [
    ["product", "price", "quantity"],
    ["Apple", 1.2, 50],
    ["Banana", 0.5, 100],
    ["Cherry", 3.0, 30],
]

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

После выполнения этого кода inventory.csv будет содержать:

product,price,quantity
Apple,1.2,50
Banana,0.5,100
Cherry,3.0,30

Используйте writer.writerow(row) для записи одной строки или writer.writerows(rows) для записи нескольких сразу. Оба метода принимают любой итерируемый объект.

Почему newline="" важно при записи

На Windows Python открывает текстовые файлы в режиме, который переводит \n в \r\n. Модуль csv также по умолчанию использует окончания строк \r\n. В совокупности это даёт \r\r\n — пустую строку между каждой строкой данных при открытии файла в другой программе. Передача newline="" подавляет лишнее преобразование и позволяет csv самому управлять окончаниями строк.

Чтение CSV-файлов с помощью csv.DictReader

DictReader преобразует каждую строку в OrderedDict (или обычный dict в Python 3.8+), где ключами служат имена столбцов из строки заголовка. Это предпочтительный подход, когда столбцы имеют значимые имена и вы хотите обращаться к ним по имени, а не по индексу.

Чтение CSV-файла в виде последовательности словарей

import csv

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

Вывод:

Alice — New York
Bob — London

DictReader автоматически читает первую строку как заголовок. Вы можете переопределить это, передав аргумент fieldnames:

import csv

# File has no header; provide field names explicitly
with open("data_no_header.csv", newline="") as f:
    reader = csv.DictReader(f, fieldnames=["name", "age", "city"])
    for row in reader:
        print(row)

Атрибут reader.fieldnames всегда содержит список используемых имён столбцов, что удобно для проверки перед обработкой строк.

Запись CSV-файлов с помощью csv.DictWriter

DictWriter — это аналог DictReader для записи. Вы заранее задаёте имена столбцов, а затем записываете словари — writer сам сопоставляет каждый ключ с нужным столбцом.

Запись списка словарей в CSV-файл

import csv

people = [
    {"name": "Alice", "age": 30, "city": "New York"},
    {"name": "Bob", "age": 25, "city": "London"},
]

fieldnames = ["name", "age", "city"]

with open("people_out.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()          # writes the column-name row
    writer.writerows(people)

Результирующий файл:

name,age,city
Alice,30,New York
Bob,25,London

writeheader() использует список fieldnames, переданный при создании объекта. Вызовите его один раз перед любыми вызовами writerow().

Обработка лишних или отсутствующих ключей

По умолчанию DictWriter вызывает ValueError, если словарь содержит ключ, которого нет в fieldnames. Изменить это поведение можно с помощью параметра extrasaction:

writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")

И наоборот, если в словаре отсутствует ключ, writer записывает пустую строку для этого поля, если только вы не задали значение по умолчанию через restval:

writer = csv.DictWriter(f, fieldnames=fieldnames, restval="N/A")

Нестандартные разделители и экранирование

CSV-файлы в реальном мире не всегда используют запятую в качестве разделителя. Широко распространены файлы с разделителем-табуляцией (TSV) и файлы с разделителем-вертикальной чертой. Используйте параметр delimiter для их обработки:

Чтение файла с разделителем-табуляцией

import csv

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

Запись файла с разделителем-вертикальной чертой

import csv

with open("output.psv", "w", newline="") as f:
    writer = csv.writer(f, delimiter="|")
    writer.writerow(["id", "name", "score"])
    writer.writerow([1, "Alice", 98])
    writer.writerow([2, "Bob", 87])

Результирующий файл:

id|name|score
1|Alice|98
2|Bob|87

Константы экранирования

Параметр quoting управляет тем, какие поля будут заключены в кавычки в выводе:

КонстантаЗначениеПоведение
csv.QUOTE_MINIMAL0Кавычки только для полей, содержащих разделитель, символ кавычки или перенос строки (по умолчанию)
csv.QUOTE_ALL1Заключать все поля в кавычки
csv.QUOTE_NONNUMERIC2Заключать в кавычки все нечисловые поля; reader преобразует поля без кавычек в float
csv.QUOTE_NONE3Никогда не использовать кавычки; вызвать ошибку, если разделитель появляется в поле

Принудительное заключение всех полей в кавычки

import csv, io

output = io.StringIO()
writer = csv.writer(output, quoting=csv.QUOTE_ALL)
writer.writerow(["name", "bio"])
writer.writerow(["Alice", "Engineer, New York"])
print(output.getvalue())

Вывод:

"name","bio"
"Alice","Engineer, New York"

Использование io.StringIO для работы с CSV в памяти

Когда нет необходимости обращаться к файловой системе — например, в тестах или при обработке CSV-данных, полученных из API — используйте io.StringIO в качестве файлоподобного объекта:

Разбор CSV из строки

import csv
import io

raw = "name,score\nAlice,95\nBob,87\n"

reader = csv.DictReader(io.StringIO(raw))
for row in reader:
    print(row["name"], "scored", row["score"])

Вывод:

Alice scored 95
Bob scored 87

Распространённые ошибки

Все значения являются строками

csv.reader и DictReader всегда возвращают строки. Преобразовывайте значения явно:

age = int(row["age"])
price = float(row["price"])

Проблемы с кодировкой

Открывайте файлы с правильной кодировкой, чтобы избежать UnicodeDecodeError. UTF-8 — наиболее распространённая кодировка для современных CSV-файлов, но файлы, экспортированные из Excel, могут использовать latin-1 или cp1252:

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

Пустые строки

Если CSV-файл содержит пустые строки между строками данных, csv.reader возвращает для них пустые списки []. Отфильтруйте их:

import csv

with open("data.csv", newline="") as f:
    reader = csv.reader(f)
    for row in reader:
        if not row:        # skip blank lines
            continue
        print(row)

Обработка ошибок

Оборачивайте операции с файлами в блок try/except для корректной обработки ситуаций с отсутствующим файлом или ошибкой доступа:

import csv

try:
    with open("data.csv", newline="") as f:
        reader = csv.reader(f)
        for row in reader:
            print(row)
except FileNotFoundError:
    print("Error: data.csv was not found.")
except PermissionError:
    print("Error: no permission to read data.csv.")

csv и Pandas для больших файлов

Модуль csv идеально подходит для:

  • Файлов малого и среднего размера (до нескольких сотен МБ)
  • Скриптов, в которых Pandas не установлен
  • Ситуаций, где вам нужен детальный контроль над чтением и записью

Для больших наборов данных, сложной фильтрации или агрегационных операций сторонняя библиотека pandas предоставляет pd.read_csv() и DataFrame.to_csv(), которые работают значительно быстрее и обладают более богатыми возможностями.

Итоговый пример

Следующий пример читает CSV-файл, фильтрует строки по условию и записывает отфильтрованные результаты в новый файл:

Фильтрация строк и запись нового CSV-файла

import csv

input_file = "inventory.csv"
output_file = "expensive.csv"

with open(input_file, newline="") as infile, \
     open(output_file, "w", newline="") as outfile:

    reader = csv.DictReader(infile)
    writer = csv.DictWriter(outfile, fieldnames=reader.fieldnames)

    writer.writeheader()
    for row in reader:
        if float(row["price"]) >= 1.0:
            writer.writerow(row)

print(f"Filtered rows written to {output_file}.")

Этот подход — открытие обоих файлов в одном блоке with, потоковая передача строк от reader к writer — позволяет обрабатывать файлы любого размера, не загружая всё содержимое в память сразу.

Связанные главы

Практика

Практика
Which csv module class maps each CSV row to a dictionary keyed by column names?
Which csv module class maps each CSV row to a dictionary keyed by column names?
Was this page helpful?