存储Python字典

310

我习惯使用CSV文件将数据输入和输出Python,但这样做存在明显的挑战。是否有简单的方法可以将字典(或一组字典)存储在JSON或pickle文件中?

例如:

data = {}
data ['key1'] = "keyinfo"
data ['key2'] = "keyinfo2"

我想知道如何保存这个东西,然后如何重新加载它。


8
你有阅读过 json 或者 pickle 标准模块的文档吗? - Greg Hewgill
1
请参见以下Python相关问题:如何将字典保存到文件中(pickle的替代方案)? - Martin Thoma
10个回答

619

Pickle保存:

try:
    import cPickle as pickle
except ImportError:  # Python 3.x
    import pickle

with open('data.p', 'wb') as fp:
    pickle.dump(data, fp, protocol=pickle.HIGHEST_PROTOCOL)

有关protocol参数的其他信息,请参见Pickle模块文档

Pickle加载:

with open('data.p', 'rb') as fp:
    data = pickle.load(fp)

JSON 保存:

import json

with open('data.json', 'w') as fp:
    json.dump(data, fp)

可以提供额外参数,例如 sort_keysindent,以获得漂亮的结果。参数 sort_keys 将按字母顺序对键进行排序,indent 将使用indent=N空格缩进数据结构。

json.dump(data, fp, sort_keys=True, indent=4)

JSON加载:

with open('data.json', 'r') as fp:
    data = json.load(fp)

8
JSON原生支持字典(虽然在内存中它们显然不会像Python的字典一样行为,但是出于持久性考虑,它们是相同的)。事实上,JSON中的基础单元是“对象”,其定义为{ <string> : <value>}。听起来熟悉吗?标准库中的json模块支持每种Python本地类型,并且可以很容易地扩展为支持用户定义的类,只需具备最基本的JSON知识即可。JSON主页只用3页纸就完全定义了该语言,因此易于快速吸收/理解。 - Jonathanb
2
了解pickle.dump的第三个参数也是值得的。如果文件不需要可读性,那么它可以大大加快速度。 - Steve Jessop
17
如果你在dump函数中添加sort_keysindent参数,你将得到一个更美观的结果。例如:json.dump(data, fp, sort_keys=True, indent=4)。更多信息可以在这里找到。 - juliusmh
1
你应该使用 pickle.dump(data, fp, protocol=pickle.HIGHEST_PROTOCOL) - Martin Thoma
2
对于Python 3,请使用import pickle - Melroy van den Berg
显示剩余13条评论

51

最简单的例子,直接将内容写入文件:

import json
json.dump(data, open(filename, 'wb'))
data = json.load(open(filename))

或者安全地打开/关闭:

import json
with open(filename, 'wb') as outfile:
    json.dump(data, outfile)
with open(filename) as infile:
    data = json.load(infile)
如果你想把它保存到字符串中而不是文件中:
import json
json_str = json.dumps(data)
data = json.loads(json_str)

9

此外,还可以使用速度更快的包ujson

import ujson

with open('data.json', 'wb') as fp:
    ujson.dump(data, fp)

1
这个包是否能够完成 JSON 的所有功能?我的意思是说,它是否可以完全替代 JSON? - bit_scientist

7

写入文件:

import json
myfile.write(json.dumps(mydict))

从文件中读取:
import json
mydict = json.loads(myfile.read())
< p > myfile 是您存储字典的文件的文件对象。

1
你知道JSON有一个接受文件作为参数并直接写入它们的功能吗? - user3850
1
json.dump(myfile)json.load(myfile) - Niklas R

5
如果您需要序列化,但不需要在其他程序中使用数据,我强烈推荐使用shelve模块。可以将其视为持久字典。
myData = shelve.open('/path/to/file')

# Check for values.
keyVar in myData

# Set values
myData[anotherKey] = someValue

# Save the data for future use.
myData.close()

2
如果你想存储整个字典或者加载整个字典,json 更加方便。而 shelve 只适用于一次访问一个键的情况下更好用。 - agf

5
如果你想要一个与pickle或json不同的选择,你可以使用klepto。
>>> init = {'y': 2, 'x': 1, 'z': 3}
>>> import klepto
>>> cache = klepto.archives.file_archive('memo', init, serialized=False)
>>> cache        
{'y': 2, 'x': 1, 'z': 3}
>>>
>>> # dump dictionary to the file 'memo.py'
>>> cache.dump() 
>>> 
>>> # import from 'memo.py'
>>> from memo import memo
>>> print memo
{'y': 2, 'x': 1, 'z': 3}

使用 klepto,如果你使用了 serialized=True,字典将会以pickled字典的形式被写入到 memo.pkl 文件中,而不是以明文形式。
你可以在这里获取 kleptohttps://github.com/uqfoundation/klepto dill 可能比 pickle 本身更好,因为 dill 可以序列化python中几乎任何内容。 klepto 也可以使用 dill
你可以在这里获取 dillhttps://github.com/uqfoundation/dill 前面几行的额外内容是因为 klepto 可以配置将字典存储到文件、目录上下文或SQL数据库中。无论你选择哪种后端归档,API都是相同的。它给你一个“可归档”字典,你可以使用 loaddump 方法与归档交互。

4

为了完整性,我们应该包括ConfigParser和configparser,它们分别是Python 2和3的标准库的一部分。此模块读取和写入配置/ini文件,并且(至少在Python 3中)表现出许多字典的行为。它的附加好处是您可以将多个字典存储到配置/ini文件的不同部分中并进行调用。棒极了!

Python 2.7.x示例。

import ConfigParser

config = ConfigParser.ConfigParser()

dict1 = {'key1':'keyinfo', 'key2':'keyinfo2'}
dict2 = {'k1':'hot', 'k2':'cross', 'k3':'buns'}
dict3 = {'x':1, 'y':2, 'z':3}

# Make each dictionary a separate section in the configuration
config.add_section('dict1')
for key in dict1.keys():
    config.set('dict1', key, dict1[key])
   
config.add_section('dict2')
for key in dict2.keys():
    config.set('dict2', key, dict2[key])

config.add_section('dict3')
for key in dict3.keys():
    config.set('dict3', key, dict3[key])

# Save the configuration to a file
f = open('config.ini', 'w')
config.write(f)
f.close()

# Read the configuration from a file
config2 = ConfigParser.ConfigParser()
config2.read('config.ini')

dictA = {}
for item in config2.items('dict1'):
    dictA[item[0]] = item[1]

dictB = {}
for item in config2.items('dict2'):
    dictB[item[0]] = item[1]

dictC = {}
for item in config2.items('dict3'):
    dictC[item[0]] = item[1]

print(dictA)
print(dictB)
print(dictC)

Python 3.X示例。

import configparser

config = configparser.ConfigParser()

dict1 = {'key1':'keyinfo', 'key2':'keyinfo2'}
dict2 = {'k1':'hot', 'k2':'cross', 'k3':'buns'}
dict3 = {'x':1, 'y':2, 'z':3}

# Make each dictionary a separate section in the configuration
config['dict1'] = dict1
config['dict2'] = dict2
config['dict3'] = dict3

# Save the configuration to a file
f = open('config.ini', 'w')
config.write(f)
f.close()

# Read the configuration from a file
config2 = configparser.ConfigParser()
config2.read('config.ini')

# ConfigParser objects are a lot like dictionaries, but if you really
# want a dictionary you can ask it to convert a section to a dictionary
dictA = dict(config2['dict1'] )
dictB = dict(config2['dict2'] )
dictC = dict(config2['dict3'])

print(dictA)
print(dictB)
print(dictC)

控制台输出

{'key2': 'keyinfo2', 'key1': 'keyinfo'}
{'k1': 'hot', 'k2': 'cross', 'k3': 'buns'}
{'z': '3', 'y': '2', 'x': '1'}

config.ini的内容

[dict1]
key2 = keyinfo2
key1 = keyinfo

[dict2]
k1 = hot
k2 = cross
k3 = buns

[dict3]
z = 3
y = 2
x = 1

3

如果要保存到JSON文件中,最好、最简单的方法是:

import json
with open("file.json", "wb") as f:
    f.write(json.dumps(dict).encode("utf-8"))

为什么这比另一个答案中概述的json.dump()更容易? - baxx
@baxx 你问题的答案可能是文件写入模式(参考:https://dev59.com/tlsX5IYBdhLWcg3waexx#33860227) - Cloud Cho

0

我的使用情况是将多个 JSON 对象保存到文件中,marty's answer 帮助了我一些。但是对于我的用例,答案不完整,因为它会在每次保存新条目时覆盖旧数据。

要在文件中保存多个条目,必须检查旧内容(即在写入之前读取)。一个典型的包含 JSON 数据的文件将具有根列表对象。因此,我认为我的 JSON 文件始终具有对象列表,每次添加数据时,我只需首先加载列表,将我的新数据附加到其中,并将其转储回可写实例的文件w

def saveJson(url,sc): # This function writes the two values to the file
    newdata = {'url':url,'sc':sc}
    json_path = "db/file.json"

    old_list= []
    with open(json_path) as myfile:  # Read the contents first
        old_list = json.load(myfile)
    old_list.append(newdata)

    with open(json_path,"w") as myfile:  # Overwrite the whole content
        json.dump(old_list, myfile, sort_keys=True, indent=4)

    return "success"


新的JSON文件大致看起来会像这样:
[
    {
        "sc": "a11",
        "url": "www.google.com"
    },
    {
        "sc": "a12",
        "url": "www.google.com"
    },
    {
        "sc": "a13",
        "url": "www.google.com"
    }
]

注意:这种方法必须有一个名为file.json的文件,并且其初始数据为[]

附:与原问题无关,但是这种方法也可以通过首先检查条目是否已存在(基于一个或多个键),然后只追加和保存数据来进一步改进。


0

更短的代码

只需一行代码即可保存和加载所有类型的Python变量(包括字典)。

data = {'key1': 'keyinfo', 'key2': 'keyinfo2'}

保存中:

pickle.dump(data, open('path/to/file/data.pickle', 'wb'))
   

加载中:

data_loaded = pickle.load(open('path/to/file/data.pickle', 'rb'))

也许这很明显,但在尝试缩短代码之前,我使用了顶部答案中的双行解决方案相当长一段时间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接