Документация Python неофициальный перевод

csv.md

615 строк · 34.3 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.0/library/csv.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `csv` – чтение и запись CSV-файлов89Так называемый формат CSV (Comma Separated Values – значения, разделённые запятыми) – наиболее распространённый формат импорта и экспорта электронных таблиц и баз данных. Не существует «стандарта CSV», поэтому формат определяется операционно, на основе множества приложений, которые его читают и записывают. Отсутствие стандарта означает, что в данных, создаваемых и потребляемых разными приложениями, часто существуют тонкие различия. Эти различия могут затруднять обработку CSV-файлов из нескольких источников. Тем не менее, хотя разделители и символы кавычек различаются, общий формат достаточно схож, чтобы можно было написать единый модуль, способный эффективно манипулировать такими данными, скрывая от программиста детали чтения и записи.1011Модуль `csv` предоставляет классы для чтения и записи табличных данных в формате CSV. Он позволяет программистам сказать: «записать эти данные в формате, предпочтительном для Excel» или «прочитать данные из этого файла, который был создан Excel», не вдаваясь в точные детали формата CSV, используемого Excel. Программисты также могут описывать форматы CSV, понятные другим приложениям, или определять собственные форматы CSV специального назначения.1213Объекты [`reader`](https://python-all.ru/3.0/library/csv.html#csv.reader) и [`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer) модуля `csv` читают и записывают последовательности. Программисты также могут читать и записывать данные в виде словаря, используя классы [`DictReader`](https://python-all.ru/3.0/library/csv.html#csv.DictReader) и [`DictWriter`](https://python-all.ru/3.0/library/csv.html#csv.DictWriter).1415> **Примечание**16>17> Эта версия модуля `csv` не поддерживает ввод в Юникоде. Кроме того, в настоящее время есть некоторые проблемы с символами ASCII NUL. Поэтому весь ввод должен быть в UTF-8 или в печатном ASCII для безопасности; см. примеры в разделе [*Примеры*](https://python-all.ru/3.0/library/csv.html#csv-examples). Эти ограничения будут сняты в будущем.1819> **См. также**20>21> **[**PEP 305**](https://python-all.ru/3.0/library/csv.html) - API для CSV-файлов**22>23> Предложение по улучшению Python, в котором было предложено это дополнение.2425## Содержимое модуля2627Модуль `csv` определяет следующие функции:2829#### `[csv.reader]csv.reader(csvfile[, dialect='excel'][, fmtparam])`3031Возвращает объект чтения, который будет перебирать строки в указанном *csvfile*. *csvfile* может быть любым объектом, поддерживающим протокол [*итератора*](https://python-all.ru/3.0/glossary.html#term-iterator) и возвращающим строку при каждом вызове его метода [`next()`](https://python-all.ru/3.0/library/functions.html#next) – подходят как файловые объекты, так и списки. Если *csvfile* является файловым объектом, он должен быть открыт с флагом 'b' на платформах, где это имеет значение. Необязательный параметр *dialect* может быть задан для определения набора параметров, специфичных для конкретного диалекта CSV. Это может быть экземпляр подкласса класса [`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect) или одна из строк, возвращаемых функцией [`list_dialects()`](https://python-all.ru/3.0/library/csv.html#csv.list_dialects). Другие необязательные именованные аргументы *fmtparam* могут быть переданы для переопределения отдельных параметров форматирования в текущем диалекте. Полную информацию о диалекте и параметрах форматирования см. в разделе [*Диалекты и параметры форматирования*](https://python-all.ru/3.0/library/csv.html#csv-fmt-params).3233Все считанные данные возвращаются в виде строк. Автоматическое преобразование типов данных не выполняется.3435Парсер довольно строг в отношении многострочных полей в кавычках. Ранее, если строка заканчивалась внутри поля в кавычках без завершающего символа новой строки, в возвращаемое поле вставлялся символ новой строки. Такое поведение вызывало проблемы при чтении файлов, содержащих символы возврата каретки внутри полей. Поведение было изменено: теперь поле возвращается без вставки новых строк. Как следствие, если встроенные в поля символы новой строки важны, входные данные следует разбивать на строки таким образом, чтобы сохранить символы новой строки.3637Краткий пример использования:3839```python40>>> import csv41>>> spamReader = csv.reader(open('eggs.csv'), delimiter=' ', quotechar='|')42>>> for row in spamReader:43...     print(', '.join(row))44Spam, Spam, Spam, Spam, Spam, Baked Beans45Spam, Lovely Spam, Wonderful Spam46```4748#### `[csv.writer]csv.writer(csvfile[, dialect='excel'][, fmtparam])`4950Возвращает объект записи, отвечающий за преобразование пользовательских данных в строки с разделителями в заданном файлоподобном объекте. *csvfile* может быть любым объектом с методом `write()`. Если *csvfile* является файловым объектом, он должен быть открыт с флагом 'b' на платформах, где это имеет значение. Необязательный параметр *dialect* может быть задан для определения набора параметров, специфичных для конкретного диалекта CSV. Это может быть экземпляр подкласса класса [`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect) или одна из строк, возвращаемых функцией [`list_dialects()`](https://python-all.ru/3.0/library/csv.html#csv.list_dialects). Другие необязательные именованные аргументы *fmtparam* могут быть переданы для переопределения отдельных параметров форматирования в текущем диалекте. Полную информацию о диалекте и параметрах форматирования см. в разделе [*Диалекты и параметры форматирования*](https://python-all.ru/3.0/library/csv.html#csv-fmt-params). Чтобы максимально упростить взаимодействие с модулями, реализующими DB API, значение [`None`](https://python-all.ru/3.0/library/constants.html#None) записывается как пустая строка. Хотя это необратимое преобразование, оно упрощает выгрузку значений SQL NULL в CSV-файлы без предварительной обработки данных, возвращаемых вызовом `cursor.fetch*`. Все остальные нестроковые данные перед записью преобразуются в строки с помощью [`str()`](https://python-all.ru/3.0/library/functions.html#str).5152Краткий пример использования:5354```python55>>> import csv56>>> spamWriter = csv.writer(open('eggs.csv', 'w'), delimiter=' ',57...                         quotechar='|', quoting=QUOTE_MINIMAL)58>>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans'])59>>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])60```6162#### `[csv.register_dialect]csv.register_dialect(name[, dialect][, fmtparam])`6364Связывает6566*dialect*6768с именем6970*name*7172.7374*name*7576должно быть строкой. Диалект может быть указан либо передачей подкласса7778[`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect)7980, либо через именованные аргументы8182*fmtparam*8384, либо и тем и другим, при этом именованные аргументы переопределяют параметры диалекта. Полную информацию о диалекте и параметрах форматирования см. в разделе8586[*Диалекты и параметры форматирования*](https://python-all.ru/3.0/library/csv.html#csv-fmt-params)8788.8990#### `[csv.unregister_dialect]csv.unregister_dialect(name)`9192Удаляет диалект, связанный с9394*name*9596, из реестра диалектов. Исключение9798[`Error`](https://python-all.ru/3.0/library/csv.html#csv.Error)99100возбуждается, если101102*name*103104не является зарегистрированным именем диалекта.105106#### `[csv.get_dialect]csv.get_dialect(name)`107108Возвращает диалект, связанный с109110*name*111112. Исключение113114[`Error`](https://python-all.ru/3.0/library/csv.html#csv.Error)115116возбуждается, если117118*name*119120не является зарегистрированным именем диалекта. Эта функция возвращает неизменяемый121122[`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect)123124.125126#### `[csv.list_dialects]csv.list_dialects()`127128Возвращает имена всех зарегистрированных диалектов.129130#### `[csv.field_size_limit]csv.field_size_limit([new_limit])`131132Возвращает текущий максимальный размер поля, разрешенный парсером. Если задан133134*new\_limit*135136, он становится новым лимитом.137138Модуль `csv` определяет следующие классы:139140#### `[csv.DictReader]class csv.DictReader(csvfile[, fieldnames=None[, restkey=None[, restval=None[, dialect='excel'[, *args, **kwds]]]]])`141142Create an object which operates like a regular reader but maps the information read into a dict whose keys are given by the optional143144*fieldnames*145146parameter. If the147148*fieldnames*149150parameter is omitted, the values in the first row of the151152*csvfile*153154will be used as the fieldnames. If the row read has fewer fields than the fieldnames sequence, the value of155156*restval*157158will be used as the default value. If the row read has more fields than the fieldnames sequence, the remaining data is added as a sequence keyed by the value of159160*restkey*161162. If the row read has fewer fields than the fieldnames sequence, the remaining keys take the value of the optional163164*restval*165166parameter. Any other optional or keyword arguments are passed to the underlying167168[`reader`](https://python-all.ru/3.0/library/csv.html#csv.reader)169170instance.171172#### `[csv.DictWriter]class csv.DictWriter(csvfile, fieldnames[, restval=''[, extrasaction='raise'[, dialect='excel'[, *args, **kwds]]]])`173174Создаёт объект, который работает как обычный writer, но преобразует словари в выходные строки. Параметр *fieldnames* определяет порядок, в котором значения словаря, переданного методу `writerow()`, записываются в *csvfile*. Необязательный параметр *restval* задаёт значение, которое будет записано, если в словаре отсутствует ключ из *fieldnames*. Если словарь, переданный методу `writerow()`, содержит ключ, отсутствующий в *fieldnames*, необязательный параметр *extrasaction* указывает, какое действие предпринять. Если он установлен в `'raise'`, возбуждается исключение [`ValueError`](https://python-all.ru/3.0/library/exceptions.html#exceptions.ValueError). Если установлен в `'ignore'`, дополнительные значения в словаре игнорируются. Все остальные необязательные или ключевые аргументы передаются экземпляру [`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer).175176Обратите внимание: в отличие от класса [`DictReader`](https://python-all.ru/3.0/library/csv.html#csv.DictReader), параметр *fieldnames* [`DictWriter`](https://python-all.ru/3.0/library/csv.html#csv.DictWriter) обязателен. Поскольку объекты [`dict`](https://python-all.ru/3.0/library/stdtypes.html#dict) в Python не упорядочены, недостаточно информации, чтобы определить порядок, в котором строка должна быть записана в *csvfile*.177178#### `[csv.Dialect]class csv.Dialect`179180Класс181182[`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect)183184– это класс-контейнер, используемый в основном для своих атрибутов, которые определяют параметры для конкретного экземпляра185186[`reader`](https://python-all.ru/3.0/library/csv.html#csv.reader)187188или189190[`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer)191192.193194#### `[csv.excel]class csv.excel`195196Класс197198[`excel`](https://python-all.ru/3.0/library/csv.html#csv.excel)199200определяет обычные свойства CSV-файла, созданного Excel. Он зарегистрирован под именем диалекта201202`'excel'`203204.205206#### `[csv.excel_tab]class csv.excel_tab`207208Класс209210[`excel_tab`](https://python-all.ru/3.0/library/csv.html#csv.excel_tab)211212определяет обычные свойства файла с разделителями-табуляцией, созданного Excel. Он зарегистрирован под именем диалекта213214`'excel-tab'`215216.217218#### `[csv.Sniffer]class csv.Sniffer`219220Класс [`Sniffer`](https://python-all.ru/3.0/library/csv.html#csv.Sniffer) используется для определения формата CSV-файла.221222Класс [`Sniffer`](https://python-all.ru/3.0/library/csv.html#csv.Sniffer) предоставляет два метода:223224#### `[csv.Sniffer.sniff]sniff(sample[, delimiters=None])`225226Анализирует заданный образец227228*sample*229230и возвращает подкласс231232[`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect)233234, отражающий найденные параметры. Если задан необязательный параметр235236*delimiters*237238, он интерпретируется как строка, содержащая возможные допустимые символы-разделители.239240#### `[csv.Sniffer.has_header]has_header(sample)`241242Анализирует образец текста (предположительно в формате CSV) и возвращает243244[`True`](https://python-all.ru/3.0/library/constants.html#True)245246, если первая строка выглядит как набор заголовков столбцов.247248Пример использования [`Sniffer`](https://python-all.ru/3.0/library/csv.html#csv.Sniffer):249250```python251csvfile = open("example.csv")252dialect = csv.Sniffer().sniff(csvfile.read(1024))253csvfile.seek(0)254reader = csv.reader(csvfile, dialect)255# ... здесь обрабатывается содержимое CSV-файла ...256```257258Модуль `csv` определяет следующие константы:259260#### `[csv.QUOTE_ALL]csv.QUOTE_ALL`261262Указывает объектам263264[`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer)265266заключать все поля в кавычки.267268#### `[csv.QUOTE_MINIMAL]csv.QUOTE_MINIMAL`269270Указывает объектам271272[`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer)273274заключать в кавычки только те поля, которые содержат специальные символы, такие как275276*delimiter*277278,279280*quotechar*281282или любые символы из283284*lineterminator*285286.287288#### `[csv.QUOTE_NONNUMERIC]csv.QUOTE_NONNUMERIC`289290Указывает объектам [`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer) заключать в кавычки все нечисловые поля.291292Указывает объекту чтения преобразовывать все нецитируемые поля в тип *float*.293294#### `[csv.QUOTE_NONE]csv.QUOTE_NONE`295296Указывает объектам [`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer) никогда не заключать поля в кавычки. Когда текущий *delimiter* встречается в выходных данных, перед ним ставится текущий символ *escapechar*. Если *escapechar* не задан, writer вызовет [`Error`](https://python-all.ru/3.0/library/csv.html#csv.Error), если будут встречены символы, требующие экранирования.297298Указывает объектам [`reader`](https://python-all.ru/3.0/library/csv.html#csv.reader) не выполнять никакой специальной обработки символов кавычек.299300Модуль `csv` определяет следующее исключение:301302#### `[csv.Error]exception csv.Error`303304Возбуждается любой из функций при обнаружении ошибки.305306## Диалекты и параметры форматирования307308Чтобы упростить задание формата входных и выходных записей, конкретные параметры форматирования группируются в диалекты. Диалект – это подкласс класса [`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect), имеющий набор определённых методов и единственный метод `validate()`. При создании объектов [`reader`](https://python-all.ru/3.0/library/csv.html#csv.reader) или [`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer) программист может указать строку или подкласс класса [`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect) в качестве параметра диалекта. В дополнение к параметру *dialect* или вместо него программист может также указать отдельные параметры форматирования, которые имеют те же имена, что и атрибуты, определённые ниже для класса [`Dialect`](https://python-all.ru/3.0/library/csv.html#csv.Dialect).309310Диалекты поддерживают следующие атрибуты:311312#### `[csv.Dialect.delimiter]Dialect.delimiter`313314Односимвольная строка, используемая для разделения полей. По умолчанию равна315316`','`317318.319320#### `[csv.Dialect.doublequote]Dialect.doublequote`321322Управляет тем, как экземпляры *quotechar*, появляющиеся внутри поля, должны экранироваться. Когда [`True`](https://python-all.ru/3.0/library/constants.html#True), символ удваивается. Когда [`False`](https://python-all.ru/3.0/library/constants.html#False), *escapechar* используется как префикс перед *quotechar*. По умолчанию [`True`](https://python-all.ru/3.0/library/constants.html#True).323324При выводе, если *doublequote* равно [`False`](https://python-all.ru/3.0/library/constants.html#False) и не задан *escapechar*, возникает [`Error`](https://python-all.ru/3.0/library/csv.html#csv.Error), если в поле обнаружен *quotechar*.325326#### `[csv.Dialect.escapechar]Dialect.escapechar`327328Односимвольная строка, используемая writer для экранирования329330*delimiter*331332, если333334*quoting*335336установлен в337338[`QUOTE_NONE`](https://python-all.ru/3.0/library/csv.html#csv.QUOTE_NONE)339340, и341342*quotechar*343344, если345346*doublequote*347348равно349350[`False`](https://python-all.ru/3.0/library/constants.html#False)351352. При чтении353354*escapechar*355356удаляет любое специальное значение из следующего символа. По умолчанию357358[`None`](https://python-all.ru/3.0/library/constants.html#None)359360, что отключает экранирование.361362#### `[csv.Dialect.lineterminator]Dialect.lineterminator`363364Строка, используемая для завершения строк, создаваемых [`writer`](https://python-all.ru/3.0/library/csv.html#csv.writer). По умолчанию равна `'\r\n'`.365366> **Примечание**367>368> [`reader`](https://python-all.ru/3.0/library/csv.html#csv.reader) жёстко запрограммирован распознавать `'\r'` или `'\n'` как конец строки и игнорирует *lineterminator*. Это поведение может измениться в будущем.369370#### `[csv.Dialect.quotechar]Dialect.quotechar`371372Односимвольная строка, используемая для заключения в кавычки полей, содержащих специальные символы, такие как373374*разделитель*375376или377378*quotechar*379380, или содержащих символы новой строки. По умолчанию381382`'"'`383384.385386#### `[csv.Dialect.quoting]Dialect.quoting`387388Управляет тем, когда кавычки должны генерироваться писателем и распознаваться читателем. Он может принимать любую из констант389390`QUOTE_*`391392(см. раздел393394[*Содержание модуля*](https://python-all.ru/3.0/library/csv.html#csv-contents)395396) и по умолчанию равен397398[`QUOTE_MINIMAL`](https://python-all.ru/3.0/library/csv.html#csv.QUOTE_MINIMAL)399400.401402#### `[csv.Dialect.skipinitialspace]Dialect.skipinitialspace`403404Если405406[`True`](https://python-all.ru/3.0/library/constants.html#True)407408, пробелы, непосредственно следующие за409410*разделителем*411412, игнорируются. Значение по умолчанию –413414[`False`](https://python-all.ru/3.0/library/constants.html#False)415416.417418## Объекты Reader419420Объекты-читатели (экземпляры [`DictReader`](https://python-all.ru/3.0/library/csv.html#csv.DictReader) и объекты, возвращаемые функцией [`reader()`](https://python-all.ru/3.0/library/csv.html#csv.reader)) имеют следующие открытые методы:421422#### `[csv.csvreader.next]csvreader.next()`423424Возвращает следующую строку итерируемого объекта reader в виде списка, разобранную в соответствии с текущим диалектом.425426Объекты reader имеют следующие открытые атрибуты:427428#### `[csv.csvreader.dialect]csvreader.dialect`429430Доступное только для чтения описание диалекта, используемого синтаксическим анализатором.431432#### `[csv.csvreader.line_num]csvreader.line_num`433434Количество строк, прочитанных из итератора-источника. Это число не совпадает с количеством возвращённых записей, так как записи могут занимать несколько строк.435436Объекты DictReader имеют следующий открытый атрибут:437438#### `[csv.csvreader.fieldnames]csvreader.fieldnames`439440Если этот атрибут не был передан в качестве параметра при создании объекта, он инициализируется при первом обращении или при чтении первой записи из файла.441442## Объекты Writer443444Объекты-писатели (`Writer`) (экземпляры [`DictWriter`](https://python-all.ru/3.0/library/csv.html#csv.DictWriter) и объекты, возвращаемые функцией [`writer()`](https://python-all.ru/3.0/library/csv.html#csv.writer)) имеют следующие открытые методы. *Строка* должна быть последовательностью строк или чисел для объектов `Writer` и словарём, отображающим имена полей на строки или числа (предварительно пропуская их через [`str()`](https://python-all.ru/3.0/library/functions.html#str)) для объектов [`DictWriter`](https://python-all.ru/3.0/library/csv.html#csv.DictWriter). Обратите внимание, что комплексные числа записываются в скобках. Это может вызвать проблемы у других программ, читающих CSV-файлы (если они вообще поддерживают комплексные числа).445446#### `[csv.csvwriter.writerow]csvwriter.writerow(row)`447448Записывает параметр449450*row*451452в файловый объект writer, отформатировав в соответствии с текущим диалектом.453454#### `[csv.csvwriter.writerows]csvwriter.writerows(rows)`455456Записывает все параметры457458*rows*459460(список объектов461462*row*463464, как описано выше) в файловый объект writer, форматируя в соответствии с текущим диалектом.465466Объекты Writer имеют следующий открытый атрибут:467468#### `[csv.csvwriter.dialect]csvwriter.dialect`469470Описание диалекта, используемого средством записи, доступное только для чтения.471472## Примеры473474Простейший пример чтения CSV-файла:475476```python477import csv478reader = csv.reader(open("some.csv", "rb"))479for row in reader:480    print(row)481```482483Чтение файла в альтернативном формате:484485```python486import csv487reader = csv.reader(open("passwd", "rb"), delimiter=':', quoting=csv.QUOTE_NONE)488for row in reader:489    print(row)490```491492Соответствующий простейший пример записи:493494```python495import csv496writer = csv.writer(open("some.csv", "wb"))497writer.writerows(someiterable)498```499500Регистрация нового диалекта:501502```python503import csv504505csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)506507reader = csv.reader(open("passwd", "rb"), 'unixpwd')508```509510Чуть более продвинутое использование reader – перехват и сообщение об ошибках:511512```python513import csv, sys514filename = "some.csv"515reader = csv.reader(open(filename, "rb"))516try:517    for row in reader:518        print(row)519except csv.Error as e:520    sys.exit('file %s, line %d: %s' % (filename, reader.line_num, e))521```522523И хотя модуль напрямую не поддерживает разбор строк, это можно легко сделать:524525```python526import csv527for row in csv.reader(['one,two,three']):528    print(row)529```530531Модуль `csv` напрямую не поддерживает чтение и запись Unicode, но он совместим с 8-битными данными, за исключением некоторых проблем с нулевыми символами ASCII. Поэтому можно написать функции или классы, которые будут обрабатывать кодирование и декодирование, если избегать кодировок, использующих нулевые байты, например UTF-16. Рекомендуется UTF-8.532533`unicode_csv_reader()` ниже – это [*генератор*](https://python-all.ru/3.0/glossary.html#term-generator), который оборачивает [`csv.reader`](https://python-all.ru/3.0/library/csv.html#csv.reader) для обработки данных CSV в Unicode (список строк Unicode). `utf_8_encoder()` – это [*генератор*](https://python-all.ru/3.0/glossary.html#term-generator), который кодирует строки Unicode в UTF-8, по одной строке (или строке данных) за раз. Закодированные строки разбираются CSV-читателем, и `unicode_csv_reader()` декодирует ячейки, закодированные в UTF-8, обратно в Unicode:534535```python536import csv537538def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):539    # csv.py не поддерживает Unicode; временно кодируйте как UTF-8:540    csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),541                            dialect=dialect, **kwargs)542    for row in csv_reader:543        # декодируйте UTF-8 обратно в Unicode, ячейка за ячейкой:544        yield [unicode(cell, 'utf-8') for cell in row]545546def utf_8_encoder(unicode_csv_data):547    for line in unicode_csv_data:548        yield line.encode('utf-8')549```550551Для всех остальных кодировок можно использовать следующие классы: `UnicodeReader` и `UnicodeWriter`. Они принимают дополнительный параметр *encoding* в конструкторе и гарантируют, что данные передаются реальному читателю или писателю в кодировке UTF-8:552553```python554import csv, codecs, io555556class UTF8Recoder:557    """558    Iterator that reads an encoded stream and reencodes the input to UTF-8559    """560    def __init__(self, f, encoding):561        self.reader = codecs.getreader(encoding)(f)562563    def __iter__(self):564        return self565566    def __next__(self):567        return next(self.reader).encode("utf-8")568569class UnicodeReader:570    """571    A CSV reader which will iterate over lines in the CSV file "f",572    which is encoded in the given encoding.573    """574575    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):576        f = UTF8Recoder(f, encoding)577        self.reader = csv.reader(f, dialect=dialect, **kwds)578579    def __next__(self):580        row = next(self.reader)581        return [unicode(s, "utf-8") for s in row]582583    def __iter__(self):584        return self585586class UnicodeWriter:587    """588    A CSV writer which will write rows to CSV file "f",589    which is encoded in the given encoding.590    """591592    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):593        # Redirect output to a queue594        self.queue = io.StringIO()595        self.writer = csv.writer(self.queue, dialect=dialect, **kwds)596        self.stream = f597        self.encoder = codecs.getincrementalencoder(encoding)()598599    def writerow(self, row):600        self.writer.writerow([s.encode("utf-8") for s in row])601        # Fetch UTF-8 output from the queue ...602        data = self.queue.getvalue()603        data = data.decode("utf-8")604        # ... and reencode it into the target encoding605        data = self.encoder.encode(data)606        # write to the target stream607        self.stream.write(data)608        # empty queue609        self.queue.truncate(0)610611    def writerows(self, rows):612        for row in rows:613            self.writerow(row)614```615