2016-08-24 5 views
0

Я пытаюсь использовать модуль shelve python для сохранения вывода сессии и перезагрузки позже, но я обнаружил, что если у меня есть определенные функции, то я получаю ошибку на этапе перезагрузки. Есть ли проблема с тем, как я это делаю? Я основывал свой код на ответе на How can I save all the variables in the current python session?.Сохранение функций с помощью полки

Вот некоторые простой код, который воспроизводит ошибку:

def test_fn(): #simple test function 
    return 

import shelve 
my_shelf = shelve.open('test_shelve','n') 

for key in globals().keys(): 
    try: 
     my_shelf[key] = globals()[key] 
    except: #__builtins__, my_shelf, and imported modules cannot be shelved. 
     pass 

my_shelf.close() 

Тогда, если я выхожу я могу сделать

ls -lh test_shelve* 
-rw-r--r-- 1 user group 22K Aug 24 11:16 test_shelve.bak 
-rw-r--r-- 1 user group 476K Aug 24 11:16 test_shelve.dat 
-rw-r--r-- 1 user group 22K Aug 24 11:16 test_shelve.dir 

В общем, в новой сессии IPython я хочу, чтобы иметь возможность сделать что-то например:

import shelve 
my_shelf = shelve.open('test_shelve') 
for key in my_shelf: 
    globals()[key]=my_shelf[key] 

Это вызывает ошибку при использовании ключа 'test_fn'. Вот код, чтобы показать сообщение об ошибке:

print my_shelf['test_fn'] 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
<ipython-input-4-deb481380237> in <module>() 
----> 1 print my_shelf['test_fn'] 

/home/user/anaconda2/envs/main/lib/python2.7/shelve.pyc in __getitem__(self, key) 
    120   except KeyError: 
    121    f = StringIO(self.dict[key]) 
--> 122    value = Unpickler(f).load() 
    123    if self.writeback: 
    124     self.cache[key] = value 

AttributeError: 'module' object has no attribute 'test_fn' 

Конечно, одно решение было бы исключить функции в стадии экономии, но от того, что я прочитал это должно быть возможно восстановить их с помощью этого метода, и поэтому Я задавался вопросом, не ошибаюсь ли я.

ответ

3

Вы не можете использовать shelve (или pickle, фактический протокол, используемый shelve) для хранения исполняемого кода, нет.

Что такое Ссылка на функцию (только место, где функция может быть импортирована снова). Код - это не данные, только тот факт, что вы ссылались на функцию, - это данные здесь. Pickle ожидает, что сможет загрузить тот же модуль и снова работать, когда вы загружаете сохраненную информацию.

То же самое относится к классам; если вы распиливаете ссылку на класс или распиливаете экземпляр класса, тогда сохраняется только информация для импорта класса (для повторного создания ссылки или экземпляра).

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

Это отражено в явном виде в What can be pickled and unpickled? section:

Note that functions (built-in and user-defined) are pickled by “fully qualified” name reference, not by value. This means that only the function name is pickled, along with the name of the module the function is defined in. Neither the function’s code, nor any of its function attributes are pickled. Thus the defining module must be importable in the unpickling environment, and the module must contain the named object, otherwise an exception will be raised.

Чтобы перейти в более подробно для конкретного примера: Основной скрипт, который выполняет Python называется __main__ модуль, и вы отложили функцию __main__.test_fn. То, что хранится тогда, является просто маркером, который сигнализирует, что вы ссылаетесь на глобальный и место импорта, поэтому хранятся что-то близкое к и __main__ плюс test_fn. При повторной загрузке полных данных, увидев маркер GLOBAL, модуль pickle пытается загрузить имя test_fn с модуля __main__. Так как ваш второй скрипт снова загружается как __main__, но не содержит test_fn, загрузка ссылки не выполняется.

+0

OK спасибо. Является ли проверка того, является ли объект, который я пытаюсь добавить в my_shelf, является функцией при сохранении и только добавление, если это не так, хороший способ решить проблему? Существуют ли другие типы объектов, которые могут вызвать проблемы? – PeterW

+0

@ user3798292: см. Документацию ['pickle'] (https://docs.python.org/2/library/pickle.html#what-can-be-pickled-and-unpickled) относительно того, что может и может ' t быть маринованным. Я включил эту ссылку в свой ответ. –

+0

@ user3798292: вместо того, чтобы пытаться и откладывать * все * в вашем модуле, почему бы не явно отложить все, что действительно важно для вашей проблемы? Явное здесь лучше, чем неявное. –

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