有没有一种方法可以从CSV文件中查找和设置DataType,而无需事先指定?

时间:2020-07-13 14:44:59

标签: python csv parsing types

我注意到来自Reading Data from CSV file...的user647772的一个示例

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)
 getBackData = list(parsed)

我找不到与为“解析”变量编写的代码相关的CSV Reader库。如果有人能指出我在python网站上的正确文档,我将不胜感激。

此外,我很想知道是否有一种方法可以在运行时确定数据类型并设置已解析变量的值(上述)。因此,如果我像上面那样修改上面的代码,以下实现是否有效:

parsed = "((row[0], int(row[1]), int(row[2]), int(row[3]), row[4], row[5]) for row in rawReader)"

getBackData = list(eval((parsed)))

还是有更好的方法?

1 个答案:

答案 0 :(得分:0)

parsed变量并不是csv.reader真正的特殊变量(没有CSV Reader库,csv是Python std库中的模块)。此语法是Python generator expression。尽管这段代码起作用,但是在尝试说明一个概念时,将多个概念压缩成单个语句并不总是最好的。

此代码对初学者更友好的形式如下:

reader = csv.reader(StringIO.StringIO(data), delimiter=",")

# use a conventional for loop to build up the getBackData list
getBackData = []
for row in reader:
    converted_row = (
        row[0] == 'True',
        row[1],
        int(row[2]),
        float(row[3]),
        row[4],
        )
    getBackData.append(converted_row)

甚至更干净的方法是将所有这些转换器推入convert_row函数,然后使用列表理解功能构建getBackData

def convert_row(raw):
    return (
        raw[0] == 'True',
        raw[1],
        int(raw[2]),
        float(raw[3]),
        raw[4],
        )

reader = csv.reader(StringIO.StringIO(data), delimiter=",")
getBackData = [convert_row(row) for row in reader]

然后,您可以根据需要修改convert_row函数,但readergetBackData的构造保持不变。

编辑:获取类型(测试得不是很好,但这是个主意)

def try_bool(s):
    # will convert strings "True" and "False" to bools,
    # and raise an exception otherwise
    try:
        return {"True": True, "False": False}[s]
    except KeyError:
        raise ValueError("{!r} is not a valid bool".format(s))

def get_column_types(raw):
    types = []
    for col in raw:
        for test_type in (int, float, try_bool, str):
            try:
                test_type(col)
            except ValueError:
                # fail! not data of this type
                pass
            else:
                # it worked! add test_type to list of converters
                types.append(test_type)
                break
    return types

# read the first row and get the types of each column
first_row = next(csv.reader(input_file))
col_types = get_column_types(first_row)

# now create a list of new rows with converted data items
converted = []
for row in csv.reader(input_file):
    # use zip to walk list of converters and list of columns at the same time
    converted_row = [converter(raw_value)
                         for converter, raw_value in zip(col_types, row)]
    converted.append(converted_row)