Форум сайта python.su
Доброе время суток, уважаемые.
Как победить такую вот пакость:
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
Офлайн
Пиклите весь объект и имя функции.
Это конечно overhead, но будет работать.
Офлайн
Прошу прощения, не совсем понял. Я вроде и так весь объект пытаюсь пиклить.
Но дело даже не в этом. На самом деле пиклю не я, a multiprocessing.Process.start, а параметром конструктору Process был передан экземпляр класса A.
Т.е. вместо
d = dumps(inst,HIGHEST_PROTOCOL)
p = multiprocessing.Process(target = ProcFunc,
args = (inst,))
p.start()
p.join()
Офлайн
дело в том, что вложенные методы в вашем случае - это не пиклящиеся объекты, поскольку пиклить можно только функции,
которые определены на верхнем уровне.
Можете почитать об этом здесь: 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)
Офлайн
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)
Офлайн
Спасибо за развернутый ответ, вопрос закрыт. Сам не смог в доке найти :(
Плохо только то, что если захотеть уметь регистрировать и методы объекта и глобальные функции, то придется в функции дочернего процесса их различать и по-разному обрабатывать. Но это уже вопрос проектирования сервера.
Офлайн