在python 3中使用python 2架子

时间:2014-12-15 21:45:29

标签: python python-2.7 python-3.x

我将数据存储在使用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版本直接访问旧格式?

5 个答案:

答案 0 :(得分:3)

shelve模块使用Python pickle,在不同版本的Python之间访问时可能需要协议版本。

尝试提供协议版本2:

population = shelve.open('shelved.shelf', protocol=2)

根据文件:

  

Python 2.3中引入了协议版本2。它提供了更有效的新式类型的酸洗。有关协议2带来的改进的信息,请参阅PEP 307.

这很可能是原始序列化(或酸洗)中使用的协议。

答案 1 :(得分:3)

据我所知,这是导致我问题的路径:

  • 原始书架是在Windows中使用Python 2创建的
  • Python 2 Windows默认使用bsddb作为搁置的底层数据库,因为dbm在Windows平台上不可用
  • Python 3不附带bsddb。底层数据库是Python 3 for Windows中的dumbdbm。

我最初考虑为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.bakfilename.datfilename.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')