Найти - Пользователи
Полная версия: Сериализация (pickling) объектов со ссылкой на метод (instancemethod)
Начало » Python для экспертов » Сериализация (pickling) объектов со ссылкой на метод (instancemethod)
1
kaa
Доброе время суток, уважаемые.

Как победить такую вот пакость:

from pickle import dumps, HIGHEST_PROTOCOL

class T(object):
def a():
pass

class A(object):
def __init__(self):
self.registered = {}

def b(self):
pass

def register(self, func, name=None):
if name is None:
name = func.__name__
self.registered[name] = func

t = T()
inst = A()

inst.register(t.a)
inst.register(inst.b)

d = dumps(inst,HIGHEST_PROTOCOL)
print d
Результат:

Traceback (most recent call last):
File "test.py", line 25, in <module>
d = dumps(inst,HIGHEST_PROTOCOL)
File "C:\Python26\lib\pickle.py", line 1366, in dumps
Pickler(file, protocol).dump(obj)
File "C:\Python26\lib\pickle.py", line 224, in dump
self.save(obj)
File "C:\Python26\lib\pickle.py", line 331, in save
self.save_reduce(obj=obj, *rv)
File "C:\Python26\lib\pickle.py", line 419, in save_reduce
save(state)
File "C:\Python26\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python26\lib\pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "C:\Python26\lib\pickle.py", line 686, in _batch_setitems
save(v)
File "C:\Python26\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python26\lib\pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "C:\Python26\lib\pickle.py", line 681, in _batch_setitems
save(v)
File "C:\Python26\lib\pickle.py", line 331, in save
self.save_reduce(obj=obj, *rv)
File "C:\Python26\lib\pickle.py", line 396, in save_reduce
save(cls)
File "C:\Python26\lib\pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "C:\Python26\lib\pickle.py", line 748, in save_global
(obj, module, name))
pickle.PicklingError: Can't pickle <type 'instancemethod'>: it's not found as __builtin__.instancemethod
Конструкция подобного типа используется в XML-RPC сервере, а из-за того, что он не хочет пиклиться, не удается сделать его многопроцессным.
Ed
Пиклите весь объект и имя функции.
Это конечно overhead, но будет работать.
kaa
Прошу прощения, не совсем понял. Я вроде и так весь объект пытаюсь пиклить.
Но дело даже не в этом. На самом деле пиклю не я, a multiprocessing.Process.start, а параметром конструктору Process был передан экземпляр класса A.

Т.е. вместо

d = dumps(inst,HIGHEST_PROTOCOL)
реально будет что-то вроде:

p = multiprocessing.Process(target = ProcFunc,
args = (inst,))
p.start()
p.join()
Ed
дело в том, что вложенные методы в вашем случае - это не пиклящиеся объекты, поскольку пиклить можно только функции,
которые определены на верхнем уровне.
Можете почитать об этом здесь: http://www.python.org/doc/current/library/pickle.html в разделе ‘What can be pickled and unpickled?’.

Я имел в виду нечто такое:
from pickle import dumps, loads, HIGHEST_PROTOCOL

class T(object):
def a(self):
print 'called T::a'
pass

class A(object):
def __init__(self):
self.registered = {}

def b(self):
print 'called A::b'
pass

def register(self, obj, fname):
self.registered[fname] = obj

t = T()
inst = A()

inst.register(t, 'a')
inst.register(inst, 'b')

unpickled = loads(dumps(inst,HIGHEST_PROTOCOL))

for fname, obj in unpickled.registered.iteritems():
getattr(obj, fname)()
Ed
PS: Вот как это работает в processing:
...
def ProcFunc(aobj):
for fname, obj in aobj.registered.iteritems():
getattr(obj, fname)()

p = processing.Process(target = ProcFunc, args = (inst,))
p.start()
p.join()
kaa
Спасибо за развернутый ответ, вопрос закрыт. Сам не смог в доке найти :(
Плохо только то, что если захотеть уметь регистрировать и методы объекта и глобальные функции, то придется в функции дочернего процесса их различать и по-разному обрабатывать. Но это уже вопрос проектирования сервера.
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