【问题标题】:How to avoid penalty of pickling a dict vs pickling a list如何避免腌制字典与腌制列表的惩罚
【发布时间】:2013-05-11 04:47:23
【问题描述】:

简介

我有一本格式如下的字典:

dict_list = {'S0':[[list of int],[list of int]], 'S1':[[list of int],[list of int]], ...}

通过 S0 访问的整数列表

dict_list['S0'][0] and dict_list['S0'][1]

为了提高代码的可读性,我将“list of list”改为“dict of list”如下:

dict_dict = {'S0': {'list0': [list of int], 'list1': [list of int]}, ...}

这会在访问列表时产生更易读的代码:

dict_dict['S0']['list0'] and dict_dict['S0']['list1']

泡菜问题

但是,当我将 dict_dict 腌制并保存到文件时,事实证明,拥有额外 dict 键的代价实际上与“S#”条目的数量成正比。似乎pickle没有“智能”存储字典,因为它分别存储了每个字典键。

现在,我们意识到这毕竟是 pickle 的工作方式,因为每个 'S#' 开始时可能有不同的键集。 pickle 无法事先知道我们的 dict_dict 实际上只是一个包含定期重复字段的表。

问题

我的问题是,是否有替代 dict_list 的替代方法,其中整数列表可以通过字符串键访问(如在 dict_dict 中)但没有上述泡菜惩罚?

更新:基于给定评论的实验

3,100 bytes - dict_list['S0'][0] (list.bin)
3,314 bytes - dict_dict['S0']['list0'] (dict.bin)
3,922 bytes - dict_class['S0'].list0 (class.bin)
5,855 bytes - dict_namedtuple['S0'].list0 (namedtuple.bin)

s_list = ['S0','S1','S2','S3','S4','S5','S6','S7','S8','S9','S10','S11','S12','S13','S14','S15','S0a','S1a','S2a','S3a','S4a','S5a','S6a','S7a','S8a','S9a','S10a','S11a','S12a','S13a','S14a','S15a','AA0','AA1','AA2','AA3','AA4','AA5','AA6','AA7','AA8','AA9','AA10','AA11','AA12','AA13','AA14','AA15','AA0a','AA1a','AA2a','AA3a','AA4a','AA5a','AA6a','AA7a','AA8a','AA9a','AA10a','AA11a','AA12a','AA13a','AA14a','AA15a','BB0','BB1','BB2','BB3','BB4','BB5','BB6','BB7','BB8','BB9','BB10','BB11','BB12','BB13','BB14','BB15','BB0a','BB1a','BB2a','BB3a','BB4a','BB5a','BB6a','BB7a','BB8a','BB9a','BB10a','BB11a','BB12a','BB13a','BB14a','BB15a']
num_of_s_entries = 32
list_length = 5

def pickle_n_save(dict_var, filename):
    outfile = open(filename, "wb")
    pickle.dump(dict_var, outfile)
    outfile.close()

# ------------------------------------------------------------dict_list['S0'][0]
dict_list = {}
for s in s_list[0:num_of_s_entries]:
    dict_list[s] = [[],[]]
    for pts in range(0,list_length):
        dict_list[s][0].append(randrange(1,100))
        dict_list[s][1].append(randrange(1,100)*1000)

pickle_n_save(dict_list, "list.bin")

# -----------------------------------------------------dict_dict['S0']['list0']
dict_dict = {}
for s in dict_list.keys():
    dict_dict[s] = {}
    dict_dict[s]['list0'] = dict_list[s][0]
    dict_dict[s]['list1'] = dict_list[s][1]

pickle_n_save(dict_dict, "dict.bin")

# -------------------------------------------------------dict_class['S0'].list0
class S:
    def __init__(self, list0, list1):
        self.list0 = list0
        self.list1 = list1

dict_class = {}
for s in dict_list.keys():
    dict_class[s] = S(dict_list[s][0],dict_list[s][1])

pickle_n_save(dict_class, "class.bin")

# ---------------------------------------------------dict_namedtuple['S0'].list0
S_namedtuple = namedtuple('S_namedtuple', ['list0','list1'])
dict_namedtuple = {}
for s in dict_list.keys():
    dict_namedtuple[s] = S_namedtuple(dict_list[s][0],dict_list[s][1])

pickle_n_save(dict_namedtuple, "namedtuple.bin")

【问题讨论】:

  • 我真的不明白使用'list1' 作为键比仅使用1 作为列表索引更具可读性或更好。
  • 我不知道,但我更喜欢使用 'dates' 和 'person' 作为键,而不必记住 0 代表 'dates' 而 1 代表 'person'。跨度>
  • 为什么不使用具有“日期”和“人”作为属性的类?这是否也会增加处罚?
  • @silvernightstar:嗯,那是完全不同的。但是如果你使用datesperson,那么就没有“聪明”的方式来存储它们,因为键根本不是数字。
  • 如何将list 包装为您自己定义的dict,比如mydict,在mydict 中,您使用字符串访问元素,然后将其转换为__getitem__ 方法中的数字('list0' 到 0)?

标签: python dictionary pickle


【解决方案1】:

也许您想要namedtuple

【讨论】:

  • 感谢您的建议。我尝试使用 namedtuple(原始问题的更新部分中显示的代码)。你觉得我的实现有什么问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多