2009-09-11 5 views
16

Questo è l'errore che ho ricevuto oggi su http://filmaster.com "> filmaster.com:PicklingError: Impossibile mettere sottochiave <class 'decimal.Decimal'>: non è lo stesso oggetto decimale. Decimale

PicklingError: Can't pickle : it's not the same object as decimal.Decimal

Cosa che esattamente significa che non sembra essere fare un sacco di senso ... sembra di essere collegato con Django caching Si può vedere l'intera traceback qui:?.

Traceback (most recent call last):

File "/home/filmaster/django-trunk/django/core/handlers/base.py", line 92, in get_response response = callback(request, *callback_args, **callback_kwargs)

File "/home/filmaster/film20/film20/core/film_views.py", line 193, in show_film
workflow.set_data_for_authenticated_user()

File "/home/filmaster/film20/film20/core/film_views.py", line 518, in set_data_for_authenticated_user
object_id = self.the_film.parent.id)

File "/home/filmaster/film20/film20/core/film_helper.py", line 179, in get_others_ratings
set_cache(CACHE_OTHERS_RATINGS, str(object_id) + "_" + str(user_id), userratings)

File "/home/filmaster/film20/film20/utils/cache_helper.py", line 80, in set_cache return cache.set(CACHE_MIDDLEWARE_KEY_PREFIX + full_path, result, get_time(cache_string))

File "/home/filmaster/django-trunk/django/core/cache/backends/memcached.py", line 37, in set
self._cache.set(smart_str(key), value, timeout or self.default_timeout)

File "/usr/lib/python2.5/site-packages/cmemcache.py", line 128, in set val, flags = self._convert(val)

File "/usr/lib/python2.5/site-packages/cmemcache.py", line 112, in _convert val = pickle.dumps(val, 2)

PicklingError: Can't pickle : it's not the same object as decimal.Decimal

E il codice sorgente per Filmaster può essere scaricato da qui: bitbucket.org/filmaster/filmaster-test

Qualsiasi aiuto sarà molto apprezzato.

+0

Ho ottenuto un errore simile dopo aver scritto un metodo __getstate__ errato per un oggetto per modificare il suo comportamento sottaceto. Non sei sicuro di quale sia il problema ma controlla uno di questi. – partofthething

+0

L'ho visto anche con i decoratori di classe, in particolare il six.add_metaclass – dbn

risposta

16

Una stranezza di Pickle è che il modo in cui si importa una classe prima di declassare una delle sue istanze può modificare leggermente l'oggetto sottoposto a picking. Pickle richiede di aver importato l'oggetto in modo identico prima di metterlo sott'aceto e prima di estrarlo.

Così, per esempio:

from a.b import c 
C = c() 
pickler.dump(C) 

farà un oggetto leggermente diversa (a volte) a:

from a import b 
C = b.c() 
pickler.dump(C) 

Prova a giocherellare con le vostre importazioni, potrebbe risolvere il problema.

+8

quindi come mai questo problema di pickling si verifica solo una volta in migliaia di richieste e normalmente funziona bene? – michuk

2

Ti è stato in qualche modo reload(decimal) o monkeypatch il modulo decimale per modificare la classe decimale? Queste sono le due cose che hanno maggiori probabilità di produrre un simile problema.

+0

Nessuno, niente di quel tipo. Sto solo importando la classe decimale. – michuk

17

Ho ricevuto questo errore durante l'esecuzione in un notebook jupyter. Penso che il problema era che stavo usando %load_ext autoreloadautoreload 2. Il riavvio del kernel e la riesecuzione hanno risolto il problema.

+0

Sembra che la modifica del metodo di una classe sia la causa del problema. La mia ipotesi è che il "autoreload" non stia aggiornando una definizione salvata da qualche altra parte. Il riavvio lo risolverebbe perché la definizione più recente viene caricata in entrambe le posizioni. – theindigamer

2

Ci possono essere problemi durante l'avvio di un processo con multiprocessing chiamando __init__. Ecco una demo:

import multiprocessing as mp 

class SubProcClass: 
    def __init__(self, pipe, startloop=False): 
     self.pipe = pipe 
     if startloop: 
      self.do_loop() 

    def do_loop(self): 
     while True: 
      req = self.pipe.recv() 
      self.pipe.send(req * req) 

class ProcessInitTest: 
    def __init__(self, spawn=False): 
     if spawn: 
      mp.set_start_method('spawn') 
     (self.msg_pipe_child, self.msg_pipe_parent) = mp.Pipe(duplex=True) 

    def start_process(self): 
     subproc = SubProcClass(self.msg_pipe_child) 
     self.trig_proc = mp.Process(target=subproc.do_loop, args=()) 
     self.trig_proc.daemon = True 
     self.trig_proc.start() 

    def start_process_fail(self): 
     self.trig_proc = mp.Process(target=SubProcClass.__init__, args=(self.msg_pipe_child,)) 
     self.trig_proc.daemon = True 
     self.trig_proc.start() 

    def do_square(self, num): 
     # Note: this is an synchronous usage of mp, 
     # which doesn't make sense. But this is just for demo 
     self.msg_pipe_parent.send(num) 
     msg = self.msg_pipe_parent.recv() 
     print('{}^2 = {}'.format(num, msg)) 

Ora, con il codice di cui sopra, se corriamo questo:

if __name__ == '__main__': 
    t = ProcessInitTest(spawn=True) 
    t.start_process_fail() 
    for i in range(1000): 
     t.do_square(i) 

Otteniamo questo errore:

Traceback (most recent call last): 
    File "start_class_process1.py", line 40, in <module> 
    t.start_process_fail() 
    File "start_class_process1.py", line 29, in start_process_fail 
    self.trig_proc.start() 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 105, in start 
    self._popen = self._Popen(self) 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/context.py", line 212, in _Popen 
    return _default_context.get_context().Process._Popen(process_obj) 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/context.py", line 274, in _Popen 
    return Popen(process_obj) 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_spawn_posix.py", line 33, in __init__ 
    super().__init__(process_obj) 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_fork.py", line 21, in __init__ 
    self._launch(process_obj) 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_spawn_posix.py", line 48, in _launch 
    reduction.dump(process_obj, fp) 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/reduction.py", line 59, in dump 
    ForkingPickler(file, protocol).dump(obj) 
_pickle.PicklingError: Can't pickle <function SubProcClass.__init__ at 0x10073e510>: it's not the same object as __main__.__init__ 

E se cambiamo per usare fork invece di spawn:

if __name__ == '__main__': 
    t = ProcessInitTest(spawn=False) 
    t.start_process_fail() 
    for i in range(1000): 
     t.do_square(i) 

Otteniamo questo errore:

Process Process-1: 
Traceback (most recent call last): 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 254, in _bootstrap 
    self.run() 
    File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 93, in run 
    self._target(*self._args, **self._kwargs) 
TypeError: __init__() missing 1 required positional argument: 'pipe' 

Ma se chiamiamo il metodo start_process, che non richiede __init__ nel mp.Process bersaglio, in questo modo:

if __name__ == '__main__': 
    t = ProcessInitTest(spawn=False) 
    t.start_process() 
    for i in range(1000): 
     t.do_square(i) 

Esso funziona come previsto (se siamo utilizzare spawn o fork).

0

Non riesco a spiegare perché questo sta venendo a mancare sia, ma la mia soluzione per risolvere questo problema è stato quello di cambiare tutto il mio codice di fare

from point import Point 

a

import point 

questo cambiamento e lavorato. Mi piacerebbe sapere perché ... htt