Найти - Пользователи
Полная версия: тонкости pickle
Начало » Python для экспертов » тонкости pickle
1 2
shiza
Хочу передать объект с одного компьютера на другой =)
Но, оказывается все не так просто. Вот пример.

Сохраняем объект:
import pickle

class O(object):
def __init__(self):
a1 = 0
o = O()

p = pickle.dumps(o, 2)

file('dump', 'wb').write(p)
Пытаемся загрузить объект:
import pickle

p = file('dump', 'rb').read()
o = pickle.loads(p)
print o.a1
Получается такой трейс:
Traceback (most recent call last):
File "C:\tmp5\\load.py", line 4, in <module>
o = pickle.loads(p)
File "C:\Python25\lib\pickle.py", line 1374, in loads
return Unpickler(file).load()
File "C:\Python25\lib\pickle.py", line 858, in load
dispatch[key](self)
File "C:\Python25\lib\pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "C:\Python25\lib\pickle.py", line 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'O'
Как-бы это обойти наименьшей кровью? =)
bw
> AttributeError: ‘module’ object has no attribute ‘O’
Естественно, ведь этого объекта нет в модуле-потребителе. Pickle сохраняет состояние экземпляра объекта, а не класс со всеми его методами целиком. Что бы выполнить десериализацию pickle должен иметь доступ к этому классу.
В качестве решения - вынеси описание класса O в отдельный модуль и гарантируй что на обоих концах (поставщик и потребитель) будут иметь доступ к нему. Самый естественный, пожалуй, метод для этого это использовать один и тот же пакет, в котором заключается описание класса O. Другими словами - получатель обязательно должен знать тип объекта, который ему передают.

..bw
shiza
Я надеялся на Магию, что есть какие-то механизмы для этого. ;)

bw
Самый естественный, пожалуй, метод для этого это использовать один и тот же пакет, в котором заключается описание класса O.
Это довольно сложно из-за того что надо будет эти пакеты (изменения в них) как-то синхронизировать.
Получается, придется делать какое-то общее хранилеще модулей и оттуда их подгружать. Прям целый огород.
Андрей Светлов
Чудак-человек. Сохранить класс вместе с объектом технически не сложно (но очень накладно по памяти) - а толку чуть. Все равно нужна синхронизация - дело особое, трудоемкое и специфическое. Интересно послушать, как, по предположениям, должна была бы работать инмверсальная “Магия” на, к примеру, двух даже не имеющих доступа к тернету машинах?
Или питон в добавок ко всему имеет еще одно революционное новшество - телепатический языко-зависимый канал общения, поставляющийся с дистрибутивом? :)
bw
Ну или передавать модуль (исходник) с объектом O потребителю. Тот его компилирует (не обязательно записывать этот исходник на винт, что бы он заработал, всё можно выполнить в мозге, сохранить можно байт-код в любом удобном для тебя виде, например в РСУБД :-), прописывает в sys.modules и т.п.

Для компиляции в байт-код: встроенный метод compile.
Для сериализации и десериализации полученного объекта: модуль marshal.
Для создания нового модуля: метод module модуля new.

Вот небольшой пример (сериализацию кода я не буду делать, это очень просто и не интересно):
>>> import sys, new
>>> source = """def bar():
... print '"bar" method of "%s" module'%__name__"""
>>> code = compile(source, 'foo', 'exec')
>>> module = new.module('foo')
>>> exec code in module.__dict__
>>> module.bar()
"bar" method of "foo" module
>>> sys.modules['foo'] = module
>>> import foo
>>> foo.bar()
"bar" method of "foo" module
Элементарно, Ватсон :-).
Компиляцию кода стоит делать именно на целевой машине, а не на поставщике этого кода. Ибо, возможно, будут разные платформы, например, разные версии Python.

p.s. Никто не знает, когда появится подсветка кода и будет использоваться шрифт с фиксированной шириной?

..bw
shiza
Андрей Светлов
Интересно послушать, как, по предположениям, должна была бы работать инмверсальная “Магия” на, к примеру, двух даже не имеющих доступа к тернету машинах?
Или питон в добавок ко всему имеет еще одно революционное новшество - телепатический языко-зависимый канал общения, поставляющийся с дистрибутивом? :)
Pickle же определяет зависимые объекты, и даже циклические ссылки.
Почемуб ему не обрабатывать и описание класса? Если на сам, то хоть с подсказкой. %)
Андрей Светлов
bwНе так-то все элементарно: после этого шага проблемы только начинаются. Возможно, модуль имеет зависимости - прийдется тащить еще и их. Захочется кешировать полученные результаты - чтобы проталкивать модули через сеть только один раз. Чтобы правильно все работало - следует передавать еще и версии модулей/объектов. Версии появятся разные на prodaction - к гадалке не ходи. Один клиент обновил просрамму, второй еще нет.
Так что, с моей точки зрения, проблема все же комплексная и не совсем простая. Хоть и решаемая, конечно же.
shiza
В принципе у меня уже есть механизм, который делает импорт всех модулей из базы данных.
У импорта уже есть кеширование.
Но может есть другие варианты?
Андрей Светлов
Эээ. Если приложения настолько близко, что могут разделять одну СУБД - тогда зачем вообще огород городить? Использовать ее, и дело с концом…
shiza
Решил огород не городить и позвал Оккама с бритвой:
не использую больше классы, как контейнеры для данных, а использую словари. Они пиклятся хорошо без выкрутасов =)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB