假设键和值都是可以以有意义的方式调用 sys.getsizeof 的合理类型以及所有不同的对象,您可以使用该信息将字典拆分为相等的块。
如果您希望最大块作为其除数,请首先计算总大小。如果您的最大尺寸在外部是固定的,则可以跳过此步骤:
total_size = sum(getsizeof(k) + getsizeof(v) for k, v in my_dict.items())
现在您可以迭代字典,假设整个字典的大小大致随机分布,在超过 max_size 阈值之前剪切一个新字典:
from sys import getsizeof
def split_dict(d, max_size):
result = []
current_size = 0
current_dict = {}
while d:
k, v = d.popitem()
increment = getsizeof(k) + getsizeof(v)
if increment + current_size > max_size:
result.append(current_dict)
if current_size:
current_dict = {k: v}
current_size = increment
else:
current_dict[k] = v # going to list
current_dict = {}
current_size = 0
else:
current_dict[k] = v
current_size += increment
if current_dict:
result.append(current_dict)
return result
请记住,dict.popitem 具有描述性:您实际上是从my_dict 中删除所有内容以填充较小的版本。
这是一个高度简化的例子:
>>> from string import ascii_letters
>>> d = {s: i for i, s in enumerate(ascii_letters)}
>>> total_size = sum(getsizeof(k) + getsizeof(v) for k, v in d.items())
>>> split_dict(d, total_size // 5)
[{'Z': 51, 'Y': 50, 'X': 49, 'W': 48, 'V': 47, 'U': 46, 'T': 45, 'S': 44, 'R': 43, 'Q': 42},
{'P': 41, 'O': 40, 'N': 39, 'M': 38, 'L': 37, 'K': 36, 'J': 35, 'I': 34, 'H': 33, 'G': 32},
{'F': 31, 'E': 30, 'D': 29, 'C': 28, 'B': 27, 'A': 26, 'z': 25, 'y': 24, 'x': 23, 'w': 22},
{'v': 21, 'u': 20, 't': 19, 's': 18, 'r': 17, 'q': 16, 'p': 15, 'o': 14, 'n': 13, 'm': 12},
{'l': 11, 'k': 10, 'j': 9, 'i': 8, 'h': 7, 'g': 6, 'f': 5, 'e': 4, 'd': 3, 'c': 2},
{'b': 1, 'a': 0}]
如您所见,拆分在分布方面不一定是最佳的,但它确保没有块大于max_size,除非单个条目需要更多字节。
更新不健全的价值观
如果您有任意大的嵌套值,您仍然可以在顶层拆分,但是,您必须将 getsizeof(v) 替换为更健壮的东西。例如:
from collections.abc import Mapping, Iterable
def xgetsizeof(x):
if isinstance(x, Mapping):
return getsizeof(x) + sum(xgetsizeof(k) + xgetsizeof(v) for k, v in x.items())
if isinstance(x, Iterable) and not isintance(x, str):
return getsizeof(x) + sum(xgetizeof(e) for e in x)
return getsizeof(x)
现在您还可以通过一次调用计算total_size:
total_size = xgetsizeof(d)
请注意,这比您之前看到的值要大。较早的结果是
xgetsizeof(d) - getsizeof(d)
要使解决方案真正健壮,您需要添加实例跟踪以避免循环引用和重复计算。
我继续为我的库haggis 编写了这样一个函数,称为haggis.objects.getsizeof。它的行为很像上面的xgetsizeof,但更加健壮。