Чтение данных из csv-файла и преобразование в правильный тип данных

У меня проблема. Я написал двумерный список, где каждый столбец имеет другой тип (bool, str, int, list), в csv-файл. Теперь я хочу снова прочитать данные из csv-файла. Но каждая прочитанная ячейка интерпретируется как строка.

Как я могу автоматически преобразовать данные чтения в правильный тип? Или лучше: есть ли возможность, чтобы сказать csv-reader правильный тип данных каждого столбца?

Пример данных (например, в csv-файле):

IsActive,Type,Price,States True,Cellphone,34,"[1, 2]" ,FlatTv,3.5,[2] False,Screen,100.23,"[5, 1]" True,Notebook, 50,[1] 

Как объясняют документы , считыватель CSV не выполняет автоматическое преобразование данных. У вас есть опция QUOTE_NONNUMERIC, но это приведет только к преобразованию всех некаблированных полей в поплавки. Это очень похоже на поведение других читателей csv.

Я не считаю, что модуль csv Python будет вообще полезен для этого случая. Как уже отмечали другие, literal_eval() – гораздо лучший выбор.

Следующее выполняет и преобразует:

  • строки
  • ИНТ
  • плавает
  • списки
  • словари

Вы также можете использовать его для booleans и NoneType, хотя они должны быть отформатированы соответственно для literal_eval() . LibreOffice Calc выводит логические значения заглавными буквами, когда в Python булевы являются заглавные. Кроме того, вам придется заменить пустые строки на None (без кавычек)

Я пишу импортера для mongodb, который делает все это. Ниже приведен код, который я написал до сих пор.

[ПРИМЕЧАНИЕ. Мой csv использует вкладку в качестве разделителя полей. Возможно, вы захотите добавить и обработку исключений]

 def getFieldnames(csvFile): """ Read the first row and store values in a tuple """ with open(csvFile) as csvfile: firstRow = csvfile.readlines(1) fieldnames = tuple(firstRow[0].strip('\n').split("\t")) return fieldnames def writeCursor(csvFile, fieldnames): """ Convert csv rows into an array of dictionaries All data types are automatically checked and converted """ cursor = [] # Placeholder for the dictionaries/documents with open(csvFile) as csvFile: for row in islice(csvFile, 1, None): values = list(row.strip('\n').split("\t")) for i, value in enumerate(values): nValue = ast.literal_eval(value) values[i] = nValue cursor.append(dict(zip(fieldnames, values))) return cursor 

Вы должны сопоставить свои строки:

 data = """True,foo,1,2.3,baz False,bar,7,9.8,qux""" reader = csv.reader(StringIO.StringIO(data), delimiter=",") parsed = (({'True':True}.get(row[0], False), row[1], int(row[2]), float(row[3]), row[4]) for row in reader) for row in parsed: print row 

приводит к

 (True, 'foo', 1, 2.3, 'baz') (False, 'bar', 7, 9.8, 'qux') 

Подкрепление к Джону Клементсу и кортопию за то, что вы учите меня об ast.literal_eval ! Вот что я закончил (Python 2, изменения для 3 должны быть тривиальными):

 from ast import literal_eval from csv import DictReader import csv def csv_data(filepath, **col_conversions): """Yield rows from the CSV file as dicts, with column headers as the keys. Values in the CSV rows are converted to Python values when possible, and are kept as strings otherwise. Specific conversion functions for columns may be specified via `col_conversions`: if a column's header is a key in this dict, its value will be applied as a function to the CSV data. Specify `ColumnHeader=str` if all values in the column should be interpreted as unquoted strings, but might be valid Python literals (`True`, `None`, `1`, etc.). Example usage: >>> csv_data(filepath, ... VariousWordsIncludingTrueAndFalse=str, ... NumbersOfVaryingPrecision=float, ... FloatsThatShouldBeRounded=round, ... **{'Column Header With Spaces': arbitrary_function}) """ def parse_value(key, value): if key in col_conversions: return col_conversions[key](value) try: # Interpret the string as a Python literal return literal_eval(value) except Exception: # If that doesn't work, assume it's an unquoted string return value with open(filepath) as f: # QUOTE_NONE: don't process quote characters, to avoid the value # `"2"` becoming the int `2`, rather than the string `'2'`. for row in DictReader(f, quoting=csv.QUOTE_NONE): yield {k: parse_value(k, v) for k, v in row.iteritems()} 

(Я немного насторожен, что, возможно, я пропустил некоторые угловые случаи, связанные с цитированием. Прошу прокомментировать, если вы видите какие-либо проблемы!)

Альтернатива (хотя кажется немного экстремальной) вместо использования ast.literal_eval – это модуль pyparsing доступный на PyPi, – и посмотрите, является ли образец кода http://pyparsing.wikispaces.com/file/view/parsePythonValue.py либо подходит для того, что вам требуется, или может быть легко адаптировано.