2014-12-15 4 views
4

У меня есть данные, хранящиеся в файле хранения, созданного с питоном 2,7Используйте питона 2 полки в питона 3

Когда я пытаюсь получить доступ к файлу из питона 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 

I «Я все еще могу получить доступ к полке без проблем в python 2.7, поэтому, похоже, проблема обратной совместимости. Есть ли способ прямого доступа к старому формату с новой версией python?

+0

Yup, я могу воспроизвести это. – matsjoyce

+0

Не можете ли вы просто преобразовать источник в 3, используя инструмент [2to3] (https://docs.python.org/2/library/2to3.html)? –

ответ

3

Как я теперь понимаю, вот тот путь, который приведет к моей проблеме:

  • оригинальная полка была создана с Python 2 в Windows, по умолчанию
  • Python 2 Windows, чтобы bsddb в качестве основной базы данных для стеллажей, поскольку дБмВт не доступен на платформе Windows,
  • Python 3 не поставляется с bsddb. Базовая база данных - это dumbdbm в Python 3 для Windows.

Сначала я изучил установку стороннего модуля bsddb для Python 3, но он быстро начал превращаться в хлопот. Тогда казалось, что это будет повторяющаяся проблема, когда мне понадобится использовать тот же файл на новом компьютере. Поэтому я решил преобразовать файл из 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 файлы вышел нормально, в ожидании перепроверки содержимое.

+0

Большое спасибо всем за мысли и советы. –

+0

Это работало для версий 2.7.12 и 3.5.2 Python, работающих на складе Ubuntu 16.04. –

2

Отредактировано: Возможно, вам потребуется переименовать базу данных. Читайте дальше ...

Похоже, pickle не является преступником. shelve также относится к anydbm (Python 2.x) или dbm (Python 3) для создания/открытия базы данных и хранения маринованной информации.

Я создал (вручную) файл базы данных, используя следующие:

# 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 модуле , но я не проверял документацию. Это может быть предназначено: -?

NB: Обратите внимание, что в моем случае расширение равно .db, но это зависит от базы данных, используемой по умолчанию dbm! Создайте пустую полку с помощью Python 3, чтобы выяснить, какой из них вы используете и чего она ожидает.

+0

Извините, похоже, не делает этого. –

+0

В качестве дополнительной проблемы может случиться так, что ваша платформа использует разные базы данных по умолчанию для 'anydbm' и' dbm'.В моем случае то же самое, но это не для @HenryKeiter –

+0

Я нашел сообщение, которое указывает на то, что проблема может быть связана с отсутствием поддержки db Berkeley в python 3. Попытка выяснить, как установить сторонний модуль, чтобы узнать, это поможет. Ссылка, указанная на странице https://groups.google.com/forum/#!topic/montrealpython/5TGZsB46rkE –

2

Модуль shelve использует Python pickle, которому может потребоваться версия протокола при доступе между различными версиями Python.

Try поставки версии 2 протокола:

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

Согласно документации:

Protocol version 2 was introduced in Python 2.3. It provides much more efficient pickling of new-style classes. Refer to PEP 307 for information about improvements brought by protocol 2.

Это, скорее всего, протокол, используемый в исходной сериализации (или травлением).

+1

Проверено, что это работает с Python 2.7.9 и Python 3.4.1 –

+1

Проверено, что это НЕ работает для Python 2.7.12 и 3.5.2 на Ubuntu 16.04. –

+0

Примечание. Этот ответ «работает» зависит от того, какой протокол использовался для хранения информации и использования того же протокола для ее получения. В настоящее время версии протокола «0» и «4» - только попытка версии «2» (как я предлагаю) не будет работать повсеместно. Он также предполагает, что ошибка является результатом несоответствия версии протокола. –

0

Я не думаю, что можно использовать полку Python 2 с модулем shelve Python 3. Основные файлы совершенно разные, по крайней мере, в моих тестах.

В Python 2 * полка представлена ​​в виде одного файла с именем файла, которое вы изначально дали.

В Python 3 *, полка состоит из три файлов: filename.bak, filename.dat и filename.dir. Без присутствия каких-либо из этих файлов полка не может быть открыта библиотекой Python 3 (хотя кажется, что достаточно всего файла .dat для открытия, если не фактического чтения).

@Ricardo Cárdenes дал обзор того, почему это может быть - это, вероятно, проблема с базовыми модулями базы данных, используемыми при хранении полных данных. Возможно, что базы данных обратно совместимы, но я не знаю, и быстрый поиск не выявил никаких очевидных ответов.

Я думаю, что это, скорее всего, некоторые из возможных баз данных, реализованных dbmявляются обратной совместимости, в то время как другие не являются: это может быть причиной расхождения между ответами здесь, где некоторые люди, но не все , могут открывать старые базы данных напрямую, указывая протокол.


* На каждой машине я проверил, используя Python 2.7.6 против питонов 3.2.5, 3.3.4 и 3.4.1

+0

Испытали ли вы это до того, как вы остановите его? Python3 'protocol = 2' действительно работает. –

+0

@JacobBudin Конечно, я протестировал его. 'protocol = 2' приводит к точно такой же ошибке. –

+0

@HenryKeiter Просто потому, что ваш интерфейс на полке отличается от ваших основных версий Python, это не значит, что это верно для всех. –

Смежные вопросы