web-dev-qa-db-fra.com

PicklingError: Can't pickle <class 'decimal.Decimal'>: ce n'est pas le même objet que decimal.Decimal

Voici l'erreur que j'ai eue aujourd'hui sur http://filmaster.com "> filmaster.com:

PicklingError: Can't pickle: ce n'est pas le même objet que decimal.Decimal

Qu'est-ce que cela veut dire exactement? Cela ne semble pas avoir beaucoup de sens ... Il semble être lié à la mise en cache Django. Vous pouvez voir l'intégralité de la trace ici:

Traceback (dernier appel le plus récent):

Fichier "/home/filmaster/Django-trunk/Django/core/handlers/base.py", ligne 92, dans get_response response = callback (request, * callback_args, ** callback_kwargs)

Fichier "/home/filmaster/film20/film20/core/film_views.py", ligne 193, dans show_film
workflow.set_data_for_authenticated_user ()

Fichier "/home/filmaster/film20/film20/core/film_views.py", ligne 518, dans set_data_for_authenticated_user
object_id = self.the_film.parent.id)

Fichier "/home/filmaster/film20/film20/core/film_helper.py", ligne 179, dans get_others_ratings
set_cache (CACHE_OTHERS_RATINGS, str (object_id) + "_" + str (user_id), userratings)

Fichier "/home/filmaster/film20/film20/utils/cache_helper.py", ligne 80, dans set_cache return cache.set (CACHE_MIDDLEWARE_KEY_PREFIX + full_path, result, get_time (cache_string))

Fichier "/home/filmaster/Django-trunk/Django/core/cache/backends/memcached.py", ligne 37, en jeu
self._cache.set (smart_str (clé), valeur, timeout ou self.default_timeout)

Fichier "/usr/lib/python2.5/site-packages/cmemcache.py", ligne 128, dans l'ensemble val, flags = self._convert (val)

Fichier "/usr/lib/python2.5/site-packages/cmemcache.py", ligne 112, dans _convert val = pickle.dumps (val, 2)

PicklingError: Can't pickle: ce n'est pas le même objet que decimal.Decimal

Et le code source de Filmaster peut être téléchargé ici: bitbucket.org/filmaster/filmaster-test

Toute aide sera fortement appréciée.

37
michuk

J'ai eu cette erreur lors de l'exécution dans un ordinateur portable jupyter. Je pense que le problème était que j'utilisais %load_ext autoreloadautoreload 2. Le redémarrage de mon noyau et sa relance ont résolu le problème.

56
James Owers

Une singularité de Pickle est que la façon dont vous importez une classe avant de décaper une de ses instances peut modifier subtilement l'objet mariné. Pickle nécessite que vous ayez importé l'objet à la fois avant de le décaper et avant de le décaper.

Ainsi, par exemple:

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

fera un objet subtilement différent (parfois) pour:

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

Essayez de jouer avec vos importations, cela pourrait corriger le problème.

24
Salim Fadhley

Je vais montrer le problème avec les classes simples Python en Python2.7:

In [13]: class A: pass  
In [14]: class B: pass

In [15]: A
Out[15]: <class __main__.A at 0x7f4089235738>

In [16]: B
Out[16]: <class __main__.B at 0x7f408939eb48>

In [17]: A.__name__ = "B"

In [18]: pickle.dumps(A)
---------------------------------------------------------------------------
PicklingError: Can't pickle <class __main__.B at 0x7f4089235738>: it's not the same object as __main__.B

Cette erreur est affichée parce que nous essayons de vider A, mais parce que nous avons changé son nom pour faire référence à un autre objet "B", le cornichon est en fait confondu avec quel objet à vider - classe A ou B. Apparemment, les gars du cornichon sont très intelligents et ils ont déjà vérifié ce comportement.

Solution: Vérifiez si l'objet que vous essayez de vider a un nom en conflit avec un autre objet.

J'ai démontré le débogage pour le cas présenté ci-dessus avec ipython et ipdb ci-dessous:

PicklingError: Can't pickle <class __main__.B at 0x7f4089235738>: it's not the same object as __main__.B

In [19]: debug
> /<path to pickle dir>/pickle.py(789)save_global()
    787                 raise PicklingError(
    788                     "Can't pickle %r: it's not the same object as %s.%s" %
--> 789                     (obj, module, name))
    790
    791         if self.proto >= 2:

ipdb> pp (obj, module, name)               **<------------- you are trying to dump obj which is class A from the pickle.dumps(A) call.**
(<class __main__.B at 0x7f4089235738>, '__main__', 'B')
ipdb> getattr(sys.modules[module], name)   **<------------- this is the conflicting definition in the module (__main__ here) with same name ('B' here).**
<class __main__.B at 0x7f408939eb48>

J'espère que cela vous évitera quelques maux de tête! Adios !!

9
Saim Raza

Je ne peux pas expliquer pourquoi cela échoue non plus, mais ma propre solution pour résoudre ce problème était de changer tout mon code de faire

from point import Point

à

import point

celui-ci a changé et cela a fonctionné. J'aimerais savoir pourquoi ... hth

5
Neil McGill

Il peut y avoir des problèmes pour démarrer un processus avec multiprocessing en appelant __init__. Voici une démo:

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

Maintenant, avec le code ci-dessus, si nous exécutons ceci:

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

Nous obtenons cette erreur:

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__

Et si nous le changeons pour utiliser fork au lieu de spawn:

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

Nous obtenons cette erreur:

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'

Mais si nous appelons le start_process méthode, qui n'appelle pas __init__ dans le mp.Process cible, comme ceci:

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

Cela fonctionne comme prévu (que nous utilisions spawn ou fork).

4
caleb

Avez-vous en quelque sorte reload(decimal), ou monkeypatch le module décimal pour changer la classe Decimal? Ce sont les deux choses les plus susceptibles de produire un tel problème.

3
Antoine P.

Mon problème était que j'avais une fonction avec le même nom défini deux fois dans un fichier. Je suppose donc qu'il était confus de savoir lequel il essayait de mariner.

1
Alexei Andreev

La même chose m'est arrivée

Le redémarrage du noyau a fonctionné pour moi

0
Tina

J'ai eu le même problème lors du débogage (Spyder). Tout fonctionnait normalement si vous exécutiez le programme. Mais, si je commence à déboguer, je fais face à la picklingError.

Mais, une fois que j'ai choisi l'option Exécuter dans la console dédiée dans Exécuter la configuration par fichier (raccourci: ctrl + F6) tout a fonctionné normalement comme prévu. Je ne sais pas exactement comment il s'adapte.

Remarque: Dans mon script, j'ai de nombreuses importations comme

from PyQt5.QtWidgets import *
from PyQt5.Qt import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import os, sys, re, math

Ma compréhension de base était, à cause de l'étoile (*), je recevais cette picklingError.

0
Rohithsai Sai