2016-09-14 1 views
3

Ich versuche Pickle zu verwenden, um Python-Objekte über die Leitung zwischen 2 Servern zu übertragen. Ich habe eine einfache Klasse, die Unterklassen dict und ich versuche, Gurke für die Rangierung zu verwenden:Warum python pickle nicht eine Methode als Standardargument serialisieren?

def value_is_not_none(value): 
    return value is not None 

class CustomDict(dict): 
    def __init__(self, cond=lambda x: x is not None): 
     super().__init__() 
     self.cond = cond 

    def __setitem__(self, key, value): 
     if self.cond(value): 
      dict.__setitem__(self, key, value) 

Ich versuchte zunächst pickle für die Rangierung zu verwenden, aber wenn ich un-vermarshallten erhielt ich einen Fehler an den im Zusammenhang lambda Ausdruck.

Dann habe ich versucht, das Marshalling mit dill zu tun, aber es schien, die __init__ wurde nicht aufgerufen.

Dann habe ich versucht wieder mit pickle, aber ich bestand die value_is_not_none() Funktion als cond Parameter - wieder die __init__() nicht schien aufgerufen werden, und die un-Rangierung gescheitert am __setitem__() (cond ist None).

Warum ist das? Was fehlt mir hier?

Wenn ich versuche, den folgenden Code auszuführen:

obj = CustomDict(cond=value_is_not_none) 
obj['hello'] = ['world'] 

payload = pickle.dumps(obj, protocol=pickle.HIGHEST_PROTOCOL) 
obj2 = pickle.loads(payload) 

es nicht mit

AttributeError: 'CustomDict' object has no attribute 'cond' 

Dies ist eine andere Frage als: Python, cPickle, pickling lambda functions , als ich versuchte dill mit lambda verwenden und es gescheitert Arbeit, und ich habe auch versucht, eine Funktion zu übergeben und es ist auch fehlgeschlagen.

+0

Bitte führen Sie den nicht funktionierenden Code mit dem Zurückverfolgungs es – holdenweb

+0

@holdenweb gibt - werfen Sie einen Blick auf das Beispiel i hinzugefügt und die Ausgabe. danke –

+0

@MartijnPieters - das ist eine andere Frage als: [python-cpickle-pickling-lambda-Funktionen] (http://stackoverflow.com/questions/16626429/python-cpickle-pickling-lambda-functions) wie ich es versucht habe Dill mit Lambda und es versäumt zu arbeiten, und ich habe auch versucht, eine Funktion übergeben und es auch fehlgeschlagen - alles in der Frage –

Antwort

2

pickle lädt Ihre Wörterbuchdaten vor Es hat die Attribute auf Ihrer Instanz wiederhergestellt. Daher ist das self.cond-Attribut noch nicht festgelegt, wenn __setitem__ für die Schlüssel/Wert-Paare des Wörterbuchs aufgerufen wird.

Beachten Sie, dass pickle niemals __init__ anrufen wird; Stattdessen wird eine vollständige leere Instanz erstellt und der __dict__ Attribut-Namespace direkt wiederhergestellt.

Sie haben zwei Möglichkeiten:

  • Standard cond=None und die Bedingung ignorieren, wenn es noch zu None gesetzt:

    class CustomDict(dict): 
        def __init__(self, cond=None): 
         super().__init__() 
         self.cond = cond 
    
        def __setitem__(self, key, value): 
         if getattr(self, 'cond', None) is None or self.cond(value): 
          dict.__setitem__(self, key, value) 
    

    Die getattr() es ist notwendig, da eine leere Instanz keine cond hat Attribut überhaupt (es ist nicht auf None gesetzt, das Attribut fehlt vollständig). Sie könnten cond = None zur Klasse hinzufügen:

    class CustomDict(dict): 
        cond = None 
    

    und testen Sie dann nur für if self.cond is None or self.cond(value):.

  • einen benutzerdefinierte definieren __reduce__ method zu steuern, wie das ursprüngliche Objekt wird erstellt, wenn gestellt:

    def _default_cond(v): return v is not None 
    
    class CustomDict(dict): 
        def __init__(self, cond=_default_cond): 
         super().__init__() 
         self.cond = cond 
    
        def __setitem__(self, key, value): 
         if self.cond(value): 
          dict.__setitem__(self, key, value) 
    
        def __reduce__(self): 
         return (CustomDict, (self.cond,), None, None, iter(self.items())) 
    

    __reduce__ erwartet wird, mit einem Tupel zurück:

    • A aufrufbar, die direkt gebeizt werden können (Hier ist die Klasse in Ordnung)
    • Ein Tupel von Positionsargumenten für diese aufrufbar; das erste Element auf Unpickling vergeht in der zweiten als Argumente genannt, so durch diese zu (self.cond,) Einstellung stellen wir sicher, dass die neue Instanz mit cond übergeben als Argument und jetzt wird CustomDict.__init__()erstellt wird aufgerufen werden.
    • Die nächsten 2 Positionen sind für eine __setstate__ Methode (hier ignoriert) und für listenähnliche Typen, also setzen wir diese auf None.
    • Das letzte Element ist ein Iterator für die Schlüssel-Wert-Paare, die dann für uns pickle wiederhergestellt werden.

    Bitte beachte, dass ich für cond mit einer Funktion auch hier den Standardwert ersetzt, so müssen Sie für das Beizen nicht verlassen sich auf dill.

Verwandte Themen