我将数据存储在使用python 2.7
创建的架子文件中当我尝试从python 3.4访问该文件时,出现错误:
>>> import shelve
>>> population=shelve.open('shelved.shelf')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python34\lib\shelve.py", line 239, in open
return DbfilenameShelf(filename, flag, protocol, writeback)
File "C:\Python34\lib\shelve.py", line 223, in __init__
Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback)
File "C:\Python34\lib\dbm\__init__.py", line 88, in open
raise error[0]("db type could not be determined")
dbm.error: db type could not be determined
我仍然能够在python 2.7中没有问题地访问架子,因此似乎存在向后兼容性问题。有没有办法用新的python版本直接访问旧格式?
答案 0 :(得分:3)
shelve
模块使用Python pickle
,在不同版本的Python之间访问时可能需要协议版本。
尝试提供协议版本2:
population = shelve.open('shelved.shelf', protocol=2)
根据文件:
Python 2.3中引入了协议版本2。它提供了更有效的新式类型的酸洗。有关协议2带来的改进的信息,请参阅PEP 307.
这很可能是原始序列化(或酸洗)中使用的协议。
答案 1 :(得分:3)
据我所知,这是导致我问题的路径:
我最初考虑为Python 3安装第三方bsddb模块,但它很快就变成了麻烦。然后,当我需要在新机器上使用相同的货架文件时,这似乎是一个反复出现的麻烦。所以我决定将文件从bsddb转换为dumbdbm,我的python 2和python 3安装都可以读取。
我在Python 2中运行了以下内容,这是包含bsddb和dumbdbm的版本:
import shelve
import dumbdbm
def dumbdbm_shelve(filename,flag="c"):
return shelve.Shelf(dumbdbm.open(filename,flag))
out_shelf=dumbdbm_shelve("shelved.dumbdbm.shelf")
in_shelf=shelve.open("shelved.shelf")
key_list=in_shelf.keys()
for key in key_list:
out_shelf[key]=in_shelf[key]
out_shelf.close()
in_shelf.close()
到目前为止看起来似乎dumbdbm.shelf文件没问题,等待仔细检查内容。
答案 2 :(得分:2)
已编辑:您可能需要重命名数据库。请继续阅读...
似乎pickle
似乎不是罪魁祸首。 shelve
还依赖于anydbm
(Python 2.x)或dbm
(Python 3)来创建/打开数据库并存储pickle信息。
我使用以下方法创建(手动)数据库文件:
# Python 2.7
import anydbm
anydbm.open('database2', flag='c')
和
# Python 3.4
import dbm
dbm.open('database3', flag='c')
在这两种情况下,它都会创建相同类型的数据库(可能依赖于分发,这是在Debian 7上):
$ file *
database2: Berkeley DB (Hash, version 9, native byte-order)
database3.db: Berkeley DB (Hash, version 9, native byte-order)
anydbm
可以正常打开database3.db
,正如预期的那样:
>>> anydbm.open('database3')
<dbm.dbm object at 0x7fb1089900f0>
但请注意,在指定数据库名称时缺少.db
。但dbm
上的database2
窒息,这很奇怪:
>>> dbm.open('database2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/dbm/__init__.py", line 88, in open
raise error[0]("db type could not be determined")
dbm.error: db type could not be determined
除非我将数据库名称的名称更改为database2.db
:
$ mv database2 database2.db
$ python3
>>> import dbm
>>> dbm.open('database2')
<_dbm.dbm object at 0x7fa7eaefcf50>
所以,我怀疑dbm
模块的回归,但我没有检查文档。它可能是: - ?
注意:请注意,在我的情况下,扩展名为.db
,但这取决于dbm
默认使用的数据库!使用Python 3创建一个空架子,找出你正在使用哪一个以及它期待什么。
答案 3 :(得分:0)
我不认为可以在Python 3的shelve
模块中使用Python 2架子。底层文件完全不同,至少在我的测试中。
在 Python 2 * 中,一个书架被表示为一个文件,其中包含您最初提供的文件名。
在 Python 3 * 中,一个架子由三个文件组成:filename.bak
,filename.dat
和filename.dir
。如果没有这些文件,Python 3库就无法打开架子(虽然看起来只有.dat
文件足以打开,如果不是实际读取的话。)
@Ricardo Cárdenes概述了为什么会这样 - 它可能是存储搁置数据时使用的底层数据库模块的问题。数据库可能向后兼容,但我不知道并且快速搜索没有找到任何明显的答案。
我认为dbm
实现的某些可能的数据库向后兼容可能,而其他则不是:这可能这是答案之间的差异的原因,有些人,但不是所有人,都可以通过指定协议直接打开旧数据库。
*在我测试的每台机器上,使用Python 2.7.6与Pythons 3.2.5,3.3.4和3.4.1
答案 4 :(得分:0)
berkeleydb 模块包括一个复古兼容的 搁置对象的实现。
您只需要:
import berkleydb
from berkeleydb import dbshelve as shelve
population=shelve.open('shelved.shelf')