有没有比pickle或常规Python文件更快的方法来存储大词典?

时间:2019-01-02 19:21:30

标签: python pickle

我想存储仅包含以下格式数据的字典:

fail=2 success=4

换句话说,只是一种快速的方法来检查密钥是否有效。我可以通过将一个名为{ "key1" : True, "key2" : True, ..... } 的字典存储在一个名为foo的文件中来完成此操作,然后在其他模块中按如下所示导入它:

bar.py

或者,我可以将其保存在名为from bar import foo 的泡菜文件中,并按如下所示将其导入文件的顶部:

bar.pickle

哪种方法更理想,并且更快

2 个答案:

答案 0 :(得分:3)

Python文件

使用python文件可以轻松地缓存字典,因此,如果您多次“导入”字典,则只需将其解析一次。但是,python语法很复杂,因此对于要保存的有限数据复杂度,加载文件的解析器可能没有得到很好的优化(除非您包括任意的Python对象和代码)。它易于查看和编辑,易于使用,但不容易运输。

编辑:澄清一下,原始Python文件对于人类来说很容易修改,但是对于计算机而言却很难编辑。如果您的代码对数据进行了编辑,并且您希望将其反映在字典中,那么您的工作就非常困难了:相反,请使用以下方法之一。

处理文件

如果您使用的是泡菜文件,则可以在每次使用时重新加载该文件,或者在第一次读取文件后需要一些管理代码来缓存该文件。像任意的Python代码一样,泡菜文件可能非常复杂,并且它们的加载程序可能未针对您的特定数据类型进行优化,因为像原始python文件一样,它们也可以存储大多数任意的Python对象。但是,他们很难为普通人编辑和查看,并且如果将数据四处移动,可能会遇到可移植性问题。它也只能由Python读取,并且您需要考虑使用pickle的安全性考虑,因为加载pickle文件可能会带来风险,并且只能使用受信任的文件来完成。

JSON文件

如果您存储的只是简单的对象(字典,列表,字符串,布尔值,数字),请考虑使用JSON文件格式。 Python具有内置的json模块,它与pickle一样易于使用,因此不会增加复杂性。这些文件易于存储,查看,编辑和压缩(如果需要),看起来几乎完全像python字典。它具有高度的可移植性(如今,大多数通用语言都支持读取/写入JSON文件),并且如果您需要提高文件加载速度,则ujson模块可作为标准json的快速替代产品模块。由于JSON文件格式受到相当严格的限制,所以我希望它的解析器和编写器比常规的Python或Pickle解析器(特别是使用ujson)要快得多。

答案 1 :(得分:2)

要添加到@scnerd的注释中,以下是IPython中针对不同负载情况的计时。

在这里我们创建字典并将其写入3种格式:

import random
import json
import pickle

letters = 'abcdefghijklmnopqrstuvwxyz'
d = {''.join(random.choices(letters, k=6)): random.choice([True, False]) 
     for _ in range(100000)}

# write a python file
with open('mydict.py', 'w') as fp:
    fp.write('d = {\n')
    for k,v in d.items():
        fp.write(f"'{k}':{v},\n")
    fp.write('None:False}')

# write a pickle file
with open('mydict.pickle', 'wb') as fp:
    pickle.dump(d, fp)

# write a json file
with open('mydict.json', 'wb') as fp:
    json.dump(d, fp)

Python文件:

# on first import the file will be cached.  
%%timeit -n1 -r1
from mydict import d

644 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

# after creating the __pycache__ folder, import is MUCH faster
%%timeit
from mydict import d

1.37 µs ± 54.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

问题文件:

%%timeit
with open('mydict.pickle', 'rb') as fp:
    pickle.load(fp)

52.4 ms ± 1.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

json文件:

%%timeit
with open('mydict.json', 'rb') as fp:
    json.load(fp)

81.3 ms ± 2.21 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# here is the same test with ujson
import ujson

%%timeit
with open('mydict.json', 'rb') as fp:
    ujson.load(fp)

51.2 ms ± 304 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)