На этом шаге мы рассмотрим решение этой задачи.
Вы хотите прочесть или записать данные в CSV-файл.
Для большей части CSV-данных можно использовать библиотеку csv. Предположим, что у вас есть данные о рынке акций в файле stocks.csv:
Symbol,Price,Date,Time,Change,Volume "AA",39.48,"6/11/2007","9:36am",-0.18,181800 "AIG",71.38,"6/11/2007","9:36am",-0.15,195500 "AXP",62.58,"6/11/2007","9:36am",-0.46,935000 "BA",98.31,"6/11/2007","9:36am",+0.12,104800 "C",53.08,"6/11/2007","9:36am",-0.25,360900 "CAT",78.29,"6/11/2007","9:36am",-0.23,225400
Вот как вы могли бы прочитать данные в последовательность кортежей:
import csv with open('stocks.csv') as f: f_csv = csv.reader(f) headers = next(f_csv) for row in f_csv: # Обработка строки . . . .
В приведенном выше коде строке соответствует кортеж. Поэтому для доступа к определенному полю вам нужно использовать индексирование: row[0](Symbol) и row[4](Change).
Поскольку такое индексирование часто может быть запутанным, вы можете захотеть использовать именованные кортежи. Например:
from collections import namedtuple with open('stocks.csv') as f: f_csv = csv.reader(f) headings = next(f_csv) Row = namedtuple('Row', headings) for r in f_csv: row = Row(*r) # Обработка строки . . . .
Это позволит использовать вместо индексов заголовки колонок, такие как row.Symbol и row.Change. Стоит отметить, что это сработает только в том случае, если заголовки колонок являются валидными идентификаторами Python. Если это не так, вы должны будете обработать эти заголовки (например, заменить неподходящие символы подчеркиваниями или аналогичными).
Еще одна альтернатива - прочесть данные в виде последовательности словарей. Чтобы это сделать, используйте такой код:
import csv with open('stocks.csv') as f: f_csv = csv.DictReader(f) for row in f_csv: # Обработка строки . . . .
В этой версии вы можете обращаться к элементам каждой строки, используя заголовки строки. Например, row['Symbol'] или row['Change'].
Чтобы записать данные в CSV, вы также можете использовать модуль csv, но создавая объект writer. Например:
headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume'] rows = [('AA', 39.48, '6/11/2007', '9:36am', -0.18, 181800), ('AIG', 71.38, '6/11/2007', '9:36am', -0.15, 195500), ('AXP', 62.58, '6/11/2007', '9:36am', -0.46, 935000), ] with open('stocks.csv', 'w') as f: f_csv = csv.writer(f) f_csv.writerow(headers) f_csv.writerows(rows)
Если у вас есть данные в форме последовательности словарей, сделайте так:
headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume'] rows = [{'Symbol': 'AA', 'Price': 39.48, 'Date': '6/11/2007', 'Time': '9:36am', 'Change': -0.18, 'Volume': 181800}, {'Symbol': 'AIG', 'Price': 71.38, 'Date': '6/11/2007', 'Time': '9:36am', 'Change': -0.15, 'Volume': 195500}, {'Symbol': 'AXP', 'Price': 62.58, 'Date': '6/11/2007', 'Time': '9:36am', 'Change': -0.46, 'Volume': 935000}, ] with open('stocks.csv', 'w') as f: f_csv = csv.DictWriter(f, headers) f_csv.writeheader() f_csv.writerows(rows)
Вы должны практически всегда предпочитать модуль csv ручному разрезанию и парсингу CSV-данных. Например, вы можете просто написать такой код:
with open('stocks.csv') as f: for line in f: row = line.split(',') # Обработка строки . . . .
Проблема подобного подхода в том, что придется разбираться с надоедливыми деталями. Например, если одно из полей окружено кавычками, вы должны будете их срезать. А если это закавыченное поле содержит запятую, код сломается, поскольку выдаст строку неверного размера.
По умолчанию библиотека csv запрограммирована понимать правила кодирования CSV, которые используются Microsoft Excel. Это, вероятно, наиболее распространенный вариант, и он с высокой вероятностью обеспечит вам наилучшую совместимость. Однако вы можете свериться с документацией модуля csv, и там вы найдете настройки, которые помогут работать с кодировками другого формата (например, заменить символ-разделитель и т. п.) Например, если вы хотите прочесть данные, разделенные символами табуляции, используйте вот такой код:
# Пример чтения разделенных символом табуляции значений with open('stocks.csv') as f: f_tsv = csv.reader(f, delimiter='\t') for row in f_tsv: # Обработка строки . . . .
Если вы читаете данные в CSV и конвертируете их в именованные кортежи, вам нужно быть аккуратными с валидацией заголовков колонок. Например, CSV-файл может иметь строку заголовка, содержащую невалидный символ:
Street Address,Num-Premises,Latitude,Longitude 5412 N CLARK,10,41.980262,-87.668452
Это при создании экземпляра namedtuple возбудит исключение ValueError. Чтобы обойти проблему, вам может потребоваться почистить заголовки. Например, разобраться с невалидными символами с помощью регулярного выражения:
import re with open('stocks.csv') as f: f_csv = csv.reader(f) headers = [re.sub('[Aa-zA-Z_]', '_', h) for h in next(f_csv)] Row = namedtuple('Row', headers) for r in f_csv: row = Row(*r) # Обработка строки . . . .
Важно отметить, что модуль csv не пытается интерпретировать данные или конвертировать их в какой-то другой тип, нежели строку. Если такие преобразования нужны, их вам придется выполнить самостоятельно. Вот пример выполнения дополнительных преобразований типов CSV-данных:
col_types = [str, float, str, str, float, int] with open('stocks.csv') as f: f_csv = csv.reader(f) headers = next(f_csv) for row in f_csv: # Применение преобразований к элементам строки row = tuple(convert(value) for convert, value in zip(col_types, row)) . . . .
Альтернативный пример преобразования выбранных полей словарей:
print('Reading as dicts with type conversion') field_types = [('Price', float), ('Change', float), ('Volume', int)] with open('stocks.csv') as f: for row in csv.DictReader(f): row.update((key, conversion(row[key])) for key, conversion in field_types) print(row)
В общем, вам стоит быть осторожными с такими преобразованиями. В реальном мире в CSV-файлах часто попадаются отсутствующие поля, поврежденные данные и прочие проблемы, которые могут поломать преобразования типов. Так что если ваши данные не являются гарантированно безошибочными, об этом стоит помнить (например, вы можете добавить подходящую обработку исключений).
Наконец, если ваша цель - чтение CSV-данных для выполнения анализа данных и статистических расчетов, вы можете взглянуть на пакет Pandas.
http://pandas.pydata.org/.
Pandas включает удобную функцию pandas.read_csv(), которая загружает CSV-данные в объект DataFrame. Далее вы можете провести различные статистические расчеты, отфильтровать данные и выполнить другие высокоуровневые операции.
На следующем шаге мы рассмотрим чтение и запись в формате JSON.