Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 4, 2009 15:05:41

kaa
От:
Зарегистрирован: 2009-01-11
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

Сериализация (pickling) объектов со ссылкой на метод (instancemethod)

Доброе время суток, уважаемые.

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

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 сервере, а из-за того, что он не хочет пиклиться, не удается сделать его многопроцессным.



Офлайн

#2 Фев. 4, 2009 17:13:20

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Сериализация (pickling) объектов со ссылкой на метод (instancemethod)

Пиклите весь объект и имя функции.
Это конечно overhead, но будет работать.



Офлайн

#3 Фев. 9, 2009 18:53:19

kaa
От:
Зарегистрирован: 2009-01-11
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

Сериализация (pickling) объектов со ссылкой на метод (instancemethod)

Прошу прощения, не совсем понял. Я вроде и так весь объект пытаюсь пиклить.
Но дело даже не в этом. На самом деле пиклю не я, a multiprocessing.Process.start, а параметром конструктору Process был передан экземпляр класса A.

Т.е. вместо

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

p = multiprocessing.Process(target = ProcFunc,
args = (inst,))
p.start()
p.join()



Офлайн

#4 Фев. 10, 2009 09:09:01

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Сериализация (pickling) объектов со ссылкой на метод (instancemethod)

дело в том, что вложенные методы в вашем случае - это не пиклящиеся объекты, поскольку пиклить можно только функции,
которые определены на верхнем уровне.
Можете почитать об этом здесь: 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)()



Отредактировано (Фев. 10, 2009 09:16:37)

Офлайн

#5 Фев. 10, 2009 09:15:38

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Сериализация (pickling) объектов со ссылкой на метод (instancemethod)

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()



Отредактировано (Фев. 10, 2009 09:36:12)

Офлайн

#6 Фев. 11, 2009 09:51:45

kaa
От:
Зарегистрирован: 2009-01-11
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

Сериализация (pickling) объектов со ссылкой на метод (instancemethod)

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



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version