【问题标题】:Import dictionary containings lists from csv从 csv 导入包含列表的字典
【发布时间】:2015-07-21 07:22:18
【问题描述】:

我有一个包含列表作为值的字典(见下文),并希望将其保存到 csv。到目前为止,保存工作正常,但是当我将其读回程序时,我得到以下结果,其中两个列表 [1,2,3] 和 [4,5,6] 不再是列表,而是字符串 ( “[1,2,3]”和“[4,5,6]”)。

如何将 csv 中的列表加载为列表而不是字符串?这样我就可以再次访问列表中的元素,而不是单个字符(见下文)。

nodes = []

test_list = [{'Key' : 'key1', 'List' : [1,2,3]}, 
        {'Key' : 'key2', 'List' : [4,5,6]}]

with open('list.csv', 'wb') as f:
    writer = csv.DictWriter(f, test_list[0].keys(), delimiter=';')
    writer.writeheader()
    for entry in test_list:
        writer.writerow(entry)

with open('list.csv') as f:
    dataset = csv.DictReader(f, delimiter=';')
    for row in dataset:
        nodes.append(row)

for elem in nodes:
    print elem

结果:

{'Key': 'key1', 'List': '[1, 2, 3]'}
{'Key': 'key2', 'List': '[4, 5, 6]'}

问题:

所以现在列表是字符串,我无法访问列表中的数字,因为它现在是一个字符列表。

>> print nodes[0]['List'][0] # print first number from list in first dictionary
[

有人可以帮助我或为我提供替代方案吗? 提前非常感谢!

【问题讨论】:

  • 你为什么不直接 json 字典?

标签: python list csv dictionary


【解决方案1】:

CSV 并不是真正用于以这种方式存储嵌套列表。您可以使用eval,但这是一个相当大的安全问题,因为它允许人们在您的计算机上运行代码,例如,如果您让人们将他们的文件上传到您的服务器。相反,我建议您将字典存储为 JSON 对象。这将处理以后可能出现的许多特殊情况。

import json

test_list = [{'Key' : 'key1', 'List' : [1,2,3]}, 
        {'Key' : 'key2', 'List' : [4,5,6]}]

with open('/tmp/test_list.json', 'w') as f:
    json.dump(test_list, f)

然后加载它:

with open('/tmp/test_list.json') as f:
    test_list = json.load(f)

【讨论】:

  • 您可以使用literal_eval 代替eval。这避免了安全问题,并且还为您提供了一些免费验证(如果您的格式实际上不是文字,您将得到一个很好的异常,而不是可能做错事、潜在危险或引发令人眼花缭乱的异常) .但你说得对,eval 在这里不是一个好主意,即使是 literal_eval
【解决方案2】:

我会用泡菜

import pickle

test_list = [{'Key' : 'key1', 'List' : [1,2,3]},
                {'Key' : 'key2', 'List' : [4,5,6]}]

pickle.dump(test_list,open('list.p','wb'))
test_list = pickle.load(open('list.p','rb'))
print test_list

>>> [{'List': [1, 2, 3], 'Key': 'key1'}, {'List': [4, 5, 6], 'Key': 'key2'}]

【讨论】:

  • 为什么使用pickle 而不是JSON?它具有相同的界面,但它为您提供了人类不可读或不可编辑(或 JavaScript/Ruby/etc.-可读)的结果,增加了潜在的安全漏洞等。pickle 非常适合您需要存储JSON 无法处理的数据(或者当您需要紧凑性,但不使用默认的 pickle 协议 0,这通常比 JSON 更慢且更大......),但是当 JSON 可以处理时,为什么不使用它呢?
  • 我倾向于使用pickle,因为它比JSON更灵活,例如pickle可以序列化一个类。但是,使用人类可读且可跨语言编辑的JSON 也很好。在我看来,其中任何一个都很好,我只想介绍 pickle 模块,以防 OP 尚未接触到它。
  • pickle 的问题在于非常灵活。它打开了潜在的安全漏洞和健壮性问题(例如,如果您在版本之间更改一个类,则必须小心不要破坏您的 pickle),并且调试 pickle 的乐趣远不如 JSON,等等。当您需要它时(或认为以后可能),尽管如此,它绝对值得,但作为 repr/literal_eval 的简单替代品,我认为 JSON 更好。 (虽然还是比repr/literal_eval...)
  • 这很有意义。我会尝试更多地使用 JSON。
【解决方案3】:

我同意@Jimmy 的观点:CSV 不太适合存储列表。正如他所建议的那样,切换到 JSON 是最好的现成解决方案。

如果由于某种原因您不能或不想切换到 JSON,您应该自己打包您的列表,以便它们可以作为 CSV 中的单个单元格存储和检索,并自行处理解包。 如果你所有的列表数据都是整数列表,你可以像这样打包和解包它们:

...
for entry in test_list:
    entry["List"] = ",".join( str(n) for n in entry["List"] )
    writer.writerow(entry)

# Reading in
for row in csv.DictReader(f, delimiter=';'):
    row["List"] = [ int(n) for n in row["List"].split(",") ]
    nodes.append(row)

因为你使用了“;”作为 CSV 中的字段分隔符,我使用“,”作为列表分隔符。如果您的作者正确引用,这不是必需的,但它更简洁。

【讨论】:

  • 您甚至可以在来自csv.reader(delimiter=';') 的单元格上递归地使用csv.reader(delimiter=',')。在 ActiveState 的某个地方有一个食谱可以很好地总结这一点。
  • 真正真正有趣的是从那里链接的配方,它使用引用来表示任意级别的递归。你可以想象一下用引号转义引号字符的 Excel 风格的引号是什么样子的……我想它仍然理论上是人类可编辑的,我只是还没有遇到可以做到这一点的人。 :)
  • 如果我没记错的话,没有嵌入引号的标准方法,对吧?一些系统识别反斜杠\",一些双引号"",......结果必须是不可移植性的纪念碑。这个应用程序听起来像是切换到 JSON 的典型代表。
  • 对,这就是你必须指定方言的原因(通过名称,或者通过组合所有单独的方言变体参数)。当然,猜错方言可能意味着您尝试与之交互的任何程序都可以毫无怨言地打开您的文件,但不会给出您想要的结果,这使得调试变得更加有趣......无论如何,你关于它是 JSON 的典型代表是正确的。我也赞成你的回答,但我希望 OP 接受 Jimmy C 的回答。
【解决方案4】:

这里的根本问题是 CSV 只存储字符串。因此,将list 放入 CSV 单元格本质上意味着自动将该列表字符串化,然后强制您再次解析它。

如果列表真的只是一个整数列表,literal_eval 将起作用。 (并且列表应该是只是一个整数列表,但结果实际上是不同的——无论是因为错误,还是因为恶意用户——它'会给你一个很好的错误,而不是默默地做一些危险的事情或引发一些没有意义的令人困惑的异常。)但这很少是一个好主意。 Python 的repr 并不意味着是一种数据序列化或交换格式;它旨在成为一种帮助人类程序员理解其数据的格式。

本教程的Input/Output 章节解释了 用于数据序列化和交换的选项:stdlib 中的jsonpicklecsv*。或者你可以求助于第三方模块,如PyYAML,或者将东西存储在数据库中等。如果你了解了每个模块的优缺点,json 在这种情况下是显而易见的答案,如Jimmy C's answer演示。


* 是的,您可以在 CSV 文件的一行中使用逗号分隔值列表,只要您使用不同的分隔符,或者允许 csv 引用内容。请参阅alexis's answer 了解一种简单的方法,或者搜索 ActiveState 配方以找到一种奇特的方式来使用 csv.writercsv.reader 递归地存储 2 级列表列表。但通常,您不想这样做; JSON 具有任意递归的优点,而不仅仅是 2 级递归,而且更大的优点是易于使用。

【讨论】:

    猜你喜欢
    • 2020-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    相关资源
    最近更新 更多