2009-12-21 13 views

risposta

33

Ecco un esempio molto semplice di Python 2 che dovrebbe integrare lo pickle docs.

class Foo(object): 
    def __init__(self, val=2): 
    self.val = val 
    def __getstate__(self): 
    print "I'm being pickled" 
    self.val *= 2 
    return self.__dict__ 
    def __setstate__(self, d): 
    print "I'm being unpickled with these values:", d 
    self.__dict__ = d 
    self.val *= 3 

import pickle 
f = Foo() 
f_string = pickle.dumps(f) 
f_new = pickle.loads(f_string) 
4

Questi metodi sono utilizzati per controllare come gli oggetti vengono decapitati e non caricati dal modulo pickle. Di solito questo viene gestito automaticamente, quindi, a meno che non sia necessario scavalcare il modo in cui una classe viene decapitata o non caricata, non è necessario preoccuparsene.

9

Esempio minimo

Qualunque sia esce getstate, va in setstate. Non ha bisogno di essere un dittico.

Qualsiasi cosa che esce da getstate deve essere selezionabile, ad es. costituito da built-in di base come int, str, list.

class C(object): 
    def __init__(self, i): 
     self.i = i 
    def __getstate__(self): 
     return self.i 
    def __setstate__(self, i): 
     self.i = i 
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1 

predefinito __setstate__

L'impostazione predefinita __setstate__ prende un dict.

self.__dict__ è una buona scelta come in https://stackoverflow.com/a/1939384/895245, ma possiamo costruire un noi stessi per vedere meglio ciò che sta accadendo:

class C(object): 
    def __init__(self, i): 
     self.i = i 
    def __getstate__(self): 
     return {'i': self.i} 
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1 

predefinito __getstate__

Analogamente a __setstate__.

class C(object): 
    def __init__(self, i): 
     self.i = i 
    def __setstate__(self, d): 
     self.i = d['i'] 
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1 

__slots__ oggetti non hanno __dict__

Se l'oggetto ha __slots__, allora non ha __dict__

Se avete intenzione di implementare sia get e setstate, il Predefinito- ish way is:

class C(object): 
    __slots__ = 'i' 
    def __init__(self, i): 
     self.i = i 
    def __getsate__(self): 
     return { slot: getattr(self, slot) for slot in self.__slots__ } 
    def __setsate__(self, d): 
     for slot in d: 
      setattr(self, slot, d[slot]) 
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1 

__slots__ predefinita ottenere e impostare aspetta una tupla

Se si desidera riutilizzare il default __getstate__ o __setstate__, si dovrà passare tuple intorno come:

class C(object): 
    __slots__ = 'i' 
    def __init__(self, i): 
     self.i = i 
    def __getsate__(self): 
     return (None, { slot: getattr(self, slot) for slot in self.__slots__ }) 
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1 

Non sono sicuro di cosa si tratta per.

Inheritance

prima vedere che le opere di decapaggio di default:

class C(object): 
    def __init__(self, i): 
     self.i = i 
class D(C): 
    def __init__(self, i, j): 
     super(D, self).__init__(i) 
     self.j = j 
d = pickle.loads(pickle.dumps(D(1, 2), -1)) 
assert d.i == 1 
assert d.j == 2 

Inheritance personalizzato __getstate__

Senza __slots__ è facile, dal momento che la __dict__ per D contiene il __dict__ per C, s o non abbiamo bisogno di toccare C affatto:

class C(object): 
    def __init__(self, i): 
     self.i = i 
class D(C): 
    def __init__(self, i, j): 
     super(D, self).__init__(i) 
     self.j = j 
    def __getstate__(self): 
     return self.__dict__ 
    def __setstate__(self, d): 
     self.__dict__ = d 
d = pickle.loads(pickle.dumps(D(1, 2), -1)) 
assert d.i == 1 
assert d.j == 2 

Ereditarietà e __slots__

Con __slots__, abbiamo bisogno di trasmettere alla classe base, e possono passare tuple in giro:

class C(object): 
    __slots__ = 'i' 
    def __init__(self, i): 
     self.i = i 
    def __getstate__(self): 
     return { slot: getattr(self, slot) for slot in C.__slots__ } 
    def __setstate__(self, d): 
     for slot in d: 
      setattr(self, slot, d[slot]) 

class D(C): 
    __slots__ = 'j' 
    def __init__(self, i, j): 
     super(D, self).__init__(i) 
     self.j = j 
    def __getstate__(self): 
     return (
      C.__getstate__(self), 
      { slot: getattr(self, slot) for slot in self.__slots__ } 
     ) 
    def __setstate__(self, ds): 
     C.__setstate__(self, ds[0]) 
     d = ds[1] 
     for slot in d: 
      setattr(self, slot, d[slot]) 

d = pickle.loads(pickle.dumps(D(1, 2), -1)) 
assert d.i == 1 
assert d.j == 2 

Purtroppo non è possibile riutilizzare il valore predefinito __getstate__ e __setstate__ della base: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ siamo costretti a definirlo.

Testato su Python 2.7.12. GitHub a monte: https://github.com/cirosantilli/python-cheat/blob/master/pickle_cheat.py