csv.md
1> **Источник:** https://python-all.ru/2.7/library/csv.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 13.1. [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv)– чтение и запись CSV-файлов89Новое в версии 2.3.1011Так называемый формат CSV (Comma Separated Values – значения, разделённые запятыми) – наиболее распространённый формат импорта и экспорта электронных таблиц и баз данных. Не существует «стандарта CSV», поэтому формат определяется операционно, на основе множества приложений, которые его читают и записывают. Отсутствие стандарта означает, что в данных, создаваемых и потребляемых разными приложениями, часто существуют тонкие различия. Эти различия могут затруднять обработку CSV-файлов из нескольких источников. Тем не менее, хотя разделители и символы кавычек различаются, общий формат достаточно схож, чтобы можно было написать единый модуль, способный эффективно манипулировать такими данными, скрывая от программиста детали чтения и записи.1213Модуль [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv) реализует классы для чтения и записи табличных данных в формате CSV. Он позволяет программистам сказать: «запиши эти данные в формате, предпочитаемом Excel» или «прочитай данные из этого файла, созданного Excel», не вдаваясь в точные детали формата CSV, используемого Excel. Программисты также могут описывать форматы CSV, используемые другими приложениями, или определять собственные специализированные форматы CSV.1415Объекты [`reader`](https://python-all.ru/2.7/library/csv.html#csv.reader) и [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer) модуля [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv) читают и записывают последовательности. Программисты также могут читать и записывать данные в словарной форме, используя классы [`DictReader`](https://python-all.ru/2.7/library/csv.html#csv.DictReader) и [`DictWriter`](https://python-all.ru/2.7/library/csv.html#csv.DictWriter).1617> **Примечание**18>19> Эта версия модуля [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv) не поддерживает ввод Unicode. Кроме того, в настоящее время есть некоторые проблемы с символами ASCII NUL. Поэтому весь ввод должен быть в UTF-8 или в печатаемом ASCII для безопасности; см. примеры в разделе [Примеры](https://python-all.ru/2.7/library/csv.html#csv-examples).2021> **См. также**22>23> **[**PEP 305**](https://python-all.ru/2.7/library/csv.html) - API для CSV-файлов**24>25> Предложение по улучшению Python, в котором было предложено это дополнение.2627## 13.1.1. Содержание модуля2829Модуль [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv) определяет следующие функции:3031#### `csv.reader(csvfile, dialect='excel', **fmtparams)`3233Возвращает объект чтения (reader), который будет выполнять итерацию по строкам в заданном *csvfile*. *csvfile* может быть любым объектом, поддерживающим протокол [итератора](https://python-all.ru/2.7/glossary.html#term-iterator) и возвращающим строку при каждом вызове метода `next()` – подходят как файловые объекты, так и списки. Если *csvfile* является файловым объектом, он должен быть открыт с флагом 'b' на платформах, где это имеет значение. Можно задать необязательный параметр *dialect*, который используется для определения набора параметров, специфичных для конкретного диалекта CSV. Это может быть экземпляр подкласса класса [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect) или одна из строк, возвращаемых функцией [`list_dialects()`](https://python-all.ru/2.7/library/csv.html#csv.list_dialects). Другие необязательные именованные аргументы *fmtparams* можно задать для переопределения отдельных параметров форматирования в текущем диалекте. Полные сведения о диалекте и параметрах форматирования см. в разделе [Диалекты и параметры форматирования](https://python-all.ru/2.7/library/csv.html#csv-fmt-params).3435Каждая строка, прочитанная из CSV-файла, возвращается в виде списка строк. Автоматическое преобразование типов данных не выполняется.3637Краткий пример использования:3839```python40>>> import csv41>>> with open('eggs.csv', 'rb') as csvfile:42... spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')43... for row in spamreader:44... print ', '.join(row)45Spam, Spam, Spam, Spam, Spam, Baked Beans46Spam, Lovely Spam, Wonderful Spam47```4849Изменено в версии 2.5: Теперь анализатор стал строже в отношении многострочных полей в кавычках. Ранее, если строка заканчивалась внутри поля в кавычках без завершающего символа новой строки, в возвращаемое поле вставлялся символ новой строки. Это поведение вызывало проблемы при чтении файлов, содержащих символы возврата каретки внутри полей. Поведение было изменено: теперь поле возвращается без вставки новых строк. Как следствие, если встроенные в поля символы новой строки важны, входные данные следует разбивать на строки таким образом, чтобы сохранить символы новой строки.5051#### `csv.writer(csvfile, dialect='excel', **fmtparams)`5253Возвращает объект записи (writer), отвечающий за преобразование пользовательских данных в строки с разделителями для заданного файлоподобного объекта. *csvfile* может быть любым объектом с методом `write()`. Если *csvfile* является файловым объектом, он должен быть открыт с флагом 'b' на платформах, где это имеет значение. Можно задать необязательный параметр *dialect*, который используется для определения набора параметров, специфичных для конкретного диалекта CSV. Это может быть экземпляр подкласса класса [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect) или одна из строк, возвращаемых функцией [`list_dialects()`](https://python-all.ru/2.7/library/csv.html#csv.list_dialects). Другие необязательные именованные аргументы *fmtparams* можно задать для переопределения отдельных параметров форматирования в текущем диалекте. Полные сведения о диалекте и параметрах форматирования см. в разделе [Диалекты и параметры форматирования](https://python-all.ru/2.7/library/csv.html#csv-fmt-params). Чтобы максимально упростить взаимодействие с модулями, реализующими DB API, значение [`None`](https://python-all.ru/2.7/library/constants.html#None) записывается как пустая строка. Хотя это не является обратимым преобразованием, это упрощает выгрузку значений SQL NULL в CSV-файлы без предварительной обработки данных, возвращаемых вызовом `cursor.fetch*`. Числа с плавающей точкой преобразуются в строку с помощью [`repr()`](https://python-all.ru/2.7/library/functions.html#repr) перед записью. Все остальные нестроковые данные преобразуются в строку с помощью [`str()`](https://python-all.ru/2.7/library/functions.html#str) перед записью.5455Краткий пример использования:5657```python58import csv59with open('eggs.csv', 'wb') as csvfile:60 spamwriter = csv.writer(csvfile, delimiter=' ',61 quotechar='|', quoting=csv.QUOTE_MINIMAL)62 spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])63 spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])64```6566#### `csv.register_dialect(name, [dialect, ]**fmtparams)`6768Связывает *dialect* с *name*. *name* должен быть строкой или объектом Unicode. Диалект можно задать, передав подкласс [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect), или с помощью именованных аргументов *fmtparams*, или обоими способами, при этом именованные аргументы переопределяют параметры диалекта. Полные сведения о диалекте и параметрах форматирования см. в разделе [Диалекты и параметры форматирования](https://python-all.ru/2.7/library/csv.html#csv-fmt-params).6970#### `csv.unregister_dialect(name)`7172Удаляет диалект, связанный с *name*, из реестра диалектов. Возникает исключение [`Error`](https://python-all.ru/2.7/library/csv.html#csv.Error), если *name* не является зарегистрированным именем диалекта.7374#### `csv.get_dialect(name)`7576Возвращает диалект, связанный с *name*. Если *name* не является зарегистрированным именем диалекта, вызывается исключение [`Error`](https://python-all.ru/2.7/library/csv.html#csv.Error).7778Изменено в версии 2.5: Теперь эта функция возвращает неизменяемый [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect). Ранее возвращался экземпляр запрошенного диалекта. Пользователи могли изменять базовый класс, меняя поведение активных читателей и писателей.7980#### `csv.list_dialects()`8182Возвращает имена всех зарегистрированных диалектов.8384#### `csv.field_size_limit([new_limit])`8586Возвращает текущий максимальный размер поля, разрешенный парсером. Если задан *new\_limit*, он становится новым лимитом.8788Новое в версии 2.5.8990Модуль [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv) определяет следующие классы:9192#### `class csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)`9394Создаёт объект, который работает как обычный читатель, но преобразует прочитанную информацию в словарь, ключи которого задаются необязательным параметром *fieldnames*. Параметр *fieldnames* представляет собой [последовательность](https://python-all.ru/2.7/library/collections.html#collections-abstract-base-classes), элементы которой последовательно связываются с полями входных данных. Эти элементы становятся ключами результирующего словаря. Если параметр *fieldnames* опущен, в качестве имён полей используются значения первой строки файла *f*. Если прочитанная строка содержит больше полей, чем последовательность имён полей, оставшиеся данные добавляются в виде последовательности, ключом которой является значение *restkey*. Если прочитанная строка содержит меньше полей, чем последовательность имён полей, оставшиеся ключи принимают значение необязательного параметра *restval*. Любые другие необязательные или именованные аргументы передаются базовому экземпляру [`reader`](https://python-all.ru/2.7/library/csv.html#csv.reader).9596Краткий пример использования:9798```python99>>> import csv100>>> with open('names.csv') as csvfile:101... reader = csv.DictReader(csvfile)102... for row in reader:103... print(row['first_name'], row['last_name'])104...105Baked Beans106Lovely Spam107Wonderful Spam108```109110#### `class csv.DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)`111112Создаёт объект, который работает как обычный писатель, но преобразует словари в строки вывода. Параметр *fieldnames* представляет собой [последовательность](https://python-all.ru/2.7/library/collections.html#collections-abstract-base-classes) ключей, определяющих порядок, в котором значения из словаря, переданного методу `writerow()`, записываются в файл *f*. Необязательный параметр *restval* задаёт значение, которое будет записано, если в словаре отсутствует ключ из *fieldnames*. Если словарь, переданный методу `writerow()`, содержит ключ, отсутствующий в *fieldnames*, необязательный параметр *extrasaction* указывает, какое действие предпринять. Если он установлен в `'raise'`, вызывается исключение [`ValueError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ValueError). Если он установлен в `'ignore'`, дополнительные значения в словаре игнорируются. Любые другие необязательные или именованные аргументы передаются базовому экземпляру [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer).113114Обратите внимание, что, в отличие от класса [`DictReader`](https://python-all.ru/2.7/library/csv.html#csv.DictReader), параметр *fieldnames* класса [`DictWriter`](https://python-all.ru/2.7/library/csv.html#csv.DictWriter) не является необязательным. Поскольку объекты [`dict`](https://python-all.ru/2.7/library/stdtypes.html#dict) в Python не упорядочены, недостаточно информации, чтобы определить порядок, в котором строка должна быть записана в файл *f*.115116Краткий пример использования:117118```python119import csv120121with open('names.csv', 'w') as csvfile:122 fieldnames = ['first_name', 'last_name']123 writer = csv.DictWriter(csvfile, fieldnames=fieldnames)124125 writer.writeheader()126 writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})127 writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'})128 writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})129```130131#### `class csv.Dialect`132133Класс [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect) – это контейнерный класс, используемый в первую очередь для своих атрибутов, которые задают параметры для конкретного экземпляра [`reader`](https://python-all.ru/2.7/library/csv.html#csv.reader) или [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer).134135#### `class csv.excel`136137Класс [`excel`](https://python-all.ru/2.7/library/csv.html#csv.excel) определяет обычные свойства CSV-файла, созданного в Excel. Он зарегистрирован под именем диалекта `'excel'`.138139#### `class csv.excel_tab`140141Класс [`excel_tab`](https://python-all.ru/2.7/library/csv.html#csv.excel_tab) определяет обычные свойства файла с разделителями табуляции, созданного в Excel. Он зарегистрирован под именем диалекта `'excel-tab'`.142143#### `class csv.Sniffer`144145Класс [`Sniffer`](https://python-all.ru/2.7/library/csv.html#csv.Sniffer) используется для определения формата CSV-файла.146147Класс [`Sniffer`](https://python-all.ru/2.7/library/csv.html#csv.Sniffer) предоставляет два метода:148149#### `sniff(sample, delimiters=None)`150151Анализирует переданный *sample* и возвращает подкласс [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect), отражающий найденные параметры. Если указан необязательный параметр *delimiters*, он интерпретируется как строка, содержащая возможные допустимые символы-разделители.152153#### `has_header(sample)`154155Анализирует образец текста (предположительно в формате CSV) и возвращает [`True`](https://python-all.ru/2.7/library/constants.html#True), если первая строка выглядит как набор заголовков столбцов.156157Пример использования [`Sniffer`](https://python-all.ru/2.7/library/csv.html#csv.Sniffer):158159```python160with open('example.csv', 'rb') as csvfile:161 dialect = csv.Sniffer().sniff(csvfile.read(1024))162 csvfile.seek(0)163 reader = csv.reader(csvfile, dialect)164 # ... здесь обрабатывается содержимое CSV-файла ...165```166167Модуль [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv) определяет следующие константы:168169#### `csv.QUOTE_ALL`170171Указывает объектам [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer) заключать все поля в кавычки.172173#### `csv.QUOTE_MINIMAL`174175Указывает объектам [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer) заключать в кавычки только те поля, которые содержат специальные символы, такие как *разделитель*, *символ кавычки* или любой из символов *терминатора строки*.176177#### `csv.QUOTE_NONNUMERIC`178179Указывает объектам [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer) заключать все нечисловые поля в кавычки.180181Указывает объекту чтения преобразовывать все нецитируемые поля в тип *float*.182183#### `csv.QUOTE_NONE`184185Указывает объектам [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer) никогда не заключать поля в кавычки. Если текущий *разделитель* встречается в выходных данных, перед ним ставится текущий символ *escapechar*. Если *escapechar* не задан, объект writer вызовет [`Error`](https://python-all.ru/2.7/library/csv.html#csv.Error), если встретятся символы, требующие экранирования.186187Указывает [`reader`](https://python-all.ru/2.7/library/csv.html#csv.reader) не выполнять специальной обработки символов кавычек.188189Модуль [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv) определяет следующее исключение:190191#### `exception csv.Error`192193Возбуждается любой из функций при обнаружении ошибки.194195## 13.1.2. Диалекты и параметры форматирования196197Чтобы упростить задание формата входных и выходных записей, определённые параметры форматирования группируются в диалекты. Диалект – это подкласс класса [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect), имеющий набор определённых методов и единственный метод `validate()`. При создании объектов [`reader`](https://python-all.ru/2.7/library/csv.html#csv.reader) или [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer) программист может указать в качестве параметра dialect строку или подкласс класса [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect). В дополнение к параметру *dialect* или вместо него программист может также указать отдельные параметры форматирования, имена которых совпадают с атрибутами класса [`Dialect`](https://python-all.ru/2.7/library/csv.html#csv.Dialect), определёнными ниже.198199Диалекты поддерживают следующие атрибуты:200201#### `Dialect.delimiter`202203Односимвольная строка, используемая для разделения полей. По умолчанию равна `','`.204205#### `Dialect.doublequote`206207Управляет тем, как должны заключаться в кавычки экземпляры *quotechar*, встречающиеся внутри поля. Когда [`True`](https://python-all.ru/2.7/library/constants.html#True), символ удваивается. Когда [`False`](https://python-all.ru/2.7/library/constants.html#False), *escapechar* используется в качестве префикса для *quotechar*. По умолчанию [`True`](https://python-all.ru/2.7/library/constants.html#True).208209При выводе, если *doublequote* равно [`False`](https://python-all.ru/2.7/library/constants.html#False) и *escapechar* не задан, возбуждается [`Error`](https://python-all.ru/2.7/library/csv.html#csv.Error), если в поле обнаружен *quotechar*.210211#### `Dialect.escapechar`212213Односимвольная строка, используемая объектом writer для экранирования *разделителя*, если для *quoting* установлено значение [`QUOTE_NONE`](https://python-all.ru/2.7/library/csv.html#csv.QUOTE_NONE), и *quotechar*, если *doublequote* равно [`False`](https://python-all.ru/2.7/library/constants.html#False). При чтении *escapechar* снимает особое значение со следующего символа. По умолчанию [`None`](https://python-all.ru/2.7/library/constants.html#None), что отключает экранирование.214215#### `Dialect.lineterminator`216217Строка, используемая для завершения строк, создаваемых [`writer`](https://python-all.ru/2.7/library/csv.html#csv.writer). По умолчанию равна `'\r\n'`.218219> **Примечание**220>221> Модуль [`reader`](https://python-all.ru/2.7/library/csv.html#csv.reader) жёстко запрограммирован распознавать `'\r'` или `'\n'` как конец строки и игнорировать *lineterminator*. В будущем это поведение может измениться.222223#### `Dialect.quotechar`224225Односимвольная строка, используемая для заключения в кавычки полей, содержащих специальные символы, такие как *разделитель* или *quotechar*, или содержащих символы новой строки. По умолчанию `'"'`.226227#### `Dialect.quoting`228229Управляет тем, когда кавычки должны генерироваться писателем (writer) и распознаваться читателем (reader). Может принимать любое из значений констант `QUOTE_*` (см. раздел [Содержание модуля](https://python-all.ru/2.7/library/csv.html#csv-contents)); по умолчанию [`QUOTE_MINIMAL`](https://python-all.ru/2.7/library/csv.html#csv.QUOTE_MINIMAL).230231#### `Dialect.skipinitialspace`232233Когда [`True`](https://python-all.ru/2.7/library/constants.html#True), пробелы сразу после *разделителя* игнорируются. По умолчанию [`False`](https://python-all.ru/2.7/library/constants.html#False).234235#### `Dialect.strict`236237Если `True`, при некорректном CSV-вводе вызывается исключение [`Error`](https://python-all.ru/2.7/library/csv.html#csv.Error). По умолчанию `False`.238239## 13.1.3. Объекты Reader240241Объекты reader (экземпляры [`DictReader`](https://python-all.ru/2.7/library/csv.html#csv.DictReader) и объекты, возвращаемые функцией [`reader()`](https://python-all.ru/2.7/library/csv.html#csv.reader)) имеют следующие открытые методы:242243#### `csvreader.next()`244245Возвращает следующую строку итерируемого объекта reader в виде списка, разобранную в соответствии с текущим диалектом.246247Объекты reader имеют следующие открытые атрибуты:248249#### `csvreader.dialect`250251Доступное только для чтения описание диалекта, используемого синтаксическим анализатором.252253#### `csvreader.line_num`254255Количество строк, прочитанных из итератора-источника. Это число не совпадает с количеством возвращённых записей, так как записи могут занимать несколько строк.256257Новое в версии 2.5.258259Объекты DictReader имеют следующий открытый атрибут:260261#### `csvreader.fieldnames`262263Если этот атрибут не был передан в качестве параметра при создании объекта, он инициализируется при первом обращении или при чтении первой записи из файла.264265Изменено в версии 2.6.266267## 13.1.4. Объекты Writer268269Объекты `Writer` (экземпляры [`DictWriter`](https://python-all.ru/2.7/library/csv.html#csv.DictWriter) и объекты, возвращаемые функцией [`writer()`](https://python-all.ru/2.7/library/csv.html#csv.writer)) имеют следующие открытые методы. Для объектов *row* должен быть последовательностью строк или чисел для объектов `Writer` и словарём, отображающим имена полей в строки или числа (с предварительным преобразованием через [`str()`](https://python-all.ru/2.7/library/functions.html#str)) для объектов [`DictWriter`](https://python-all.ru/2.7/library/csv.html#csv.DictWriter). Обратите внимание, что комплексные числа записываются в круглых скобках. Это может вызвать некоторые проблемы у других программ, читающих CSV-файлы (если они вообще поддерживают комплексные числа).270271#### `csvwriter.writerow(row)`272273Записывает параметр *row* в файловый объект writer, отформатировав в соответствии с текущим диалектом.274275#### `csvwriter.writerows(rows)`276277Записывает все элементы из *rows* (итерацию объектов *row*, как описано выше) в файловый объекта средства записи, форматируя в соответствии с текущим диалектом.278279Объекты Writer имеют следующий открытый атрибут:280281#### `csvwriter.dialect`282283Описание диалекта, используемого средством записи, доступное только для чтения.284285Объекты DictWriter имеют следующий открытый метод:286287#### `DictWriter.writeheader()`288289Записывает строку с названиями полей (как указано в конструкторе).290291Новое в версии 2.7.292293## 13.1.5. Примеры294295Простейший пример чтения CSV-файла:296297```python298import csv299with open('some.csv', 'rb') as f:300 reader = csv.reader(f)301 for row in reader:302 print row303```304305Чтение файла в альтернативном формате:306307```python308import csv309with open('passwd', 'rb') as f:310 reader = csv.reader(f, delimiter=':', quoting=csv.QUOTE_NONE)311 for row in reader:312 print row313```314315Соответствующий простейший пример записи:316317```python318import csv319with open('some.csv', 'wb') as f:320 writer = csv.writer(f)321 writer.writerows(someiterable)322```323324Регистрация нового диалекта:325326```python327import csv328csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)329with open('passwd', 'rb') as f:330 reader = csv.reader(f, 'unixpwd')331```332333Чуть более продвинутое использование reader – перехват и сообщение об ошибках:334335```python336import csv, sys337filename = 'some.csv'338with open(filename, 'rb') as f:339 reader = csv.reader(f)340 try:341 for row in reader:342 print row343 except csv.Error as e:344 sys.exit('file %s, line %d: %s' % (filename, reader.line_num, e))345```346347И хотя модуль напрямую не поддерживает разбор строк, это можно легко сделать:348349```python350import csv351for row in csv.reader(['one,two,three']):352 print row353```354355Модуль [`csv`](https://python-all.ru/2.7/library/csv.html#module-csv) напрямую не поддерживает чтение и запись Unicode, но он 8-битно-чист, за исключением некоторых проблем с символами ASCII NUL. Поэтому можно написать функции или классы, которые будут обрабатывать кодирование и декодирование, если избегать кодировок, использующих NUL, таких как UTF-16. Рекомендуется UTF-8.356357`unicode_csv_reader()` ниже – это [генератор](https://python-all.ru/2.7/glossary.html#term-generator), который обёртывает [`csv.reader`](https://python-all.ru/2.7/library/csv.html#csv.reader) для обработки данных Unicode CSV (списка строк Unicode). `utf_8_encoder()` – это [генератор](https://python-all.ru/2.7/glossary.html#term-generator), который кодирует строки Unicode в UTF-8 по одной строке (или строке таблицы) за раз. Закодированные строки разбираются CSV-читателем, а `unicode_csv_reader()` декодирует ячейки, закодированные в UTF-8, обратно в Unicode:358359```python360import csv361362def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):363 # csv.py не поддерживает Unicode; временно кодируйте как UTF-8:364 csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),365 dialect=dialect, **kwargs)366 for row in csv_reader:367 # декодируйте UTF-8 обратно в Unicode, ячейка за ячейкой:368 yield [unicode(cell, 'utf-8') for cell in row]369370def utf_8_encoder(unicode_csv_data):371 for line in unicode_csv_data:372 yield line.encode('utf-8')373```374375Для всех остальных кодировок можно использовать следующие классы `UnicodeReader` и `UnicodeWriter`. Они принимают дополнительный параметр *encoding* в своём конструкторе и обеспечивают передачу данных через реальный читатель или писатель, закодированных в UTF-8:376377```python378import csv, codecs, cStringIO379380class UTF8Recoder:381 """382 Итератор, который читает закодированный поток и перекодирует входные данные в UTF-8383 """384 def __init__(self, f, encoding):385 self.reader = codecs.getreader(encoding)(f)386387 def __iter__(self):388 return self389390 def next(self):391 return self.reader.next().encode("utf-8")392393class UnicodeReader:394 """395 CSV-ридер, который будет перебирать строки в CSV-файле "f",396 который закодирован в указанной кодировке.397 """398399 def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):400 f = UTF8Recoder(f, encoding)401 self.reader = csv.reader(f, dialect=dialect, **kwds)402403 def next(self):404 row = self.reader.next()405 return [unicode(s, "utf-8") for s in row]406407 def __iter__(self):408 return self409410class UnicodeWriter:411 """412 Объект для записи CSV, который будет записывать строки в CSV-файл "f",413 который закодирован в указанной кодировке.414 """415416 def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):417 # Перенаправить вывод в очередь418 self.queue = cStringIO.StringIO()419 self.writer = csv.writer(self.queue, dialect=dialect, **kwds)420 self.stream = f421 self.encoder = codecs.getincrementalencoder(encoding)()422423 def writerow(self, row):424 self.writer.writerow([s.encode("utf-8") for s in row])425 # Извлечь UTF-8 вывод из очереди ...426 data = self.queue.getvalue()427 data = data.decode("utf-8")428 # ... и перекодировать его в целевую кодировку429 data = self.encoder.encode(data)430 # записать в целевой поток431 self.stream.write(data)432 # очистить очередь433 self.queue.truncate(0)434435 def writerows(self, rows):436 for row in rows:437 self.writerow(row)438```439