web-dev-qa-db-fra.com

Quelle est l'utilisation exacte de __reduce__ dans Pickler

Je sais que pour être picklable, une classe doit écraser __reduce__, et il doit renvoyer une chaîne ou un tuple.

Comment fonctionne cette fonction? Quelle est l'utilisation exacte de __reduce__? Quand sera-t-il utilisé?

36
oyjh

Je vais voir si je peux essayer d'expliquer celui-ci.

Chaque fois que vous essayez de décaper un objet, certaines propriétés peuvent ne pas être sérialisées correctement. Par exemple, un descripteur de fichier ouvert Dans ce cas, pickle ne saura pas comment gérer l'objet et générera une erreur.

Vous pouvez indiquer au module pickle comment gérer directement ces types d'objets en mode natif dans une classe. Permet de construire l'exemple d'un objet qui a une seule propriété; un descripteur de fichier ouvert:

import pickle

class test(object):
    def __init__(self, file_path = 'test1234567890.txt'):
        self.some_file_i_have_opened = open(file_path, 'wb')  # An open file in write mode.

my_test = test()
# Now, watch what happens when we try to pickle this object:
pickle.dumps(my_test)

Il devrait échouer et donner une trace:

Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  --- snip snip a lot of lines ---
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle file objects

Cependant, si nous avions défini un __reduce__ dans notre testclass, pickle aurait su sérialiser cet objet:

import pickle

class test(object):
    def __init__(self, file_path = 'test1234567890.txt'):
        self._file_name_we_opened = file_path  # Used later in __reduce__
        self.some_file_i_have_opened = open(self._file_name_we_opened, 'wb')  # An open file in write mode.
    def __reduce__(self):
        return (self.__class__, (self._file_name_we_opened, ))  # we return a Tuple of class_name to call, and optional parameters to pass when re-creating

my_test = test()
saved_object = pickle.dumps(my_test)
print repr(saved_object)  # Just print the representation of the string of the object, because it contains newlines.

Cela devrait vous donner quelque chose comme: "c__main__\ntest\np0\n(S'test1234567890.txt'\np1\ntp2\nRp3\n.", qui peut être utilisé pour recréer l'objet avec des poignées de fichier ouvertes:

print vars(pickle.loads(saved_object))

Habituellement, la grande confusion est avec quel type d'objet __reduce__ devrait revenir. tandis que vous pouvez en savoir un peu plus sur le type d'objet à réduire qui devrait revenir dans les pages de documentation: https: //docs.python. org/3/bibliothèque/pickle.html # objet. réduire , mais en général, il a besoin d'un tuple d'au moins 2 choses:

  1. Une classe d'objets vide à appeler. Dans ce cas, self.__class__
  2. Un tuple d'arguments à passer au constructeur de classe. Dans ce cas, il s'agit d'une seule chaîne, qui est le chemin d'accès au fichier à ouvrir.

Il existe d'autres éléments facultatifs, mais vous devriez tout lire à leur sujet dans la documentation.

J'espère que cela pourra aider!

60
VooDooNOFX