3

我在尝试打开超过一定大小的搁置持久文件时遇到此异常,该大小实际上非常小(< 1MB),但我不确定确切的数字在哪里。现在,我知道 pickle 有点像 python 的混蛋,而 shelve 并不被认为是一个特别强大的解决方案,但它恰好很好地解决了我的问题(理论上),我一直无法找到原因这个例外。

Traceback (most recent call last):
  File "test_shelve.py", line 27, in <module>
    print len(f.keys())
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shelve.py", line 101, in keys
    return self.dict.keys()
SystemError: Negative size passed to PyString_FromStringAndSize

我可以始终如一地重现它,但我在谷歌上找不到太多。这是一个将重现的脚本。

import shelve
import random
import string
import pprint

f = shelve.open('test')
# f = {}

def rand_list(list_size=20, str_size=40):
    return [''.join([random.choice(string.ascii_uppercase + string.digits) for j in range(str_size)]) for i in range(list_size)]

def recursive_dict(depth=3):
    if depth==0:
        return rand_list()
    else:
        d = {}
        for k in rand_list():
            d[k] = recursive_dict(depth-1)
        return d

for k,v in recursive_dict(2).iteritems():
    f[k] = v

f.close()

f = shelve.open('test')
print len(f.keys())
4

2 回答 2

2

如果我将深度从 2 更改为 1,或者如果我在 python 3 下运行(在修复print语句并使用items()而不是iteritems()),则代码“有效”。但是,键列表显然不是在遍历 的返回值时找到的键集recursive_dict()

文档中的以下限制shelve可能适用(强调我的):

选择使用哪个数据库包(例如 dbm、gdbm 或 bsddb)取决于可用的接口。因此直接使用dbm打开数据库是不安全的。如果使用数据库,数据库也(不幸地)受到 dbm 的限制——这意味着存储在数据库中的对象(腌制表示)应该相当小,并且在极少数情况下,键冲突可能会导致数据库拒绝更新。

于 2013-05-01T21:49:25.437 回答
2

关于错误本身:

网络上流传的想法是数据大小超过了该机器上可能的最大整数(最大的 32 位(有符号)整数是 2 147 483 647),Python 将其解释为负大小。

您的代码正在运行2.7.3,因此可能是一个已修复的错误。

于 2013-05-01T21:52:38.440 回答