2010-02-05 24 views
24

Sto provando a decapitare un oggetto di una (nuova) classe che ho definito. Ma sto ottenendo il seguente errore:Perché ricevo un errore sulla mia classe che definisce __slots__ quando provo a decapitare un oggetto?

>>> with open('temp/connection.pickle','w') as f: 
... pickle.dump(c,f) 
... 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "/usr/lib/python2.5/pickle.py", line 1362, in dump 
    Pickler(file, protocol).dump(obj) 
    File "/usr/lib/python2.5/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/usr/lib/python2.5/pickle.py", line 331, in save 
    self.save_reduce(obj=obj, *rv) 
    File "/usr/lib/python2.5/pickle.py", line 419, in save_reduce 
    save(state) 
    File "/usr/lib/python2.5/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/usr/lib/python2.5/pickle.py", line 649, in save_dict 
    self._batch_setitems(obj.iteritems()) 
    File "/usr/lib/python2.5/pickle.py", line 663, in _batch_setitems 
    save(v) 
    File "/usr/lib/python2.5/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/usr/lib/python2.5/copy_reg.py", line 76, in _reduce_ex 
    raise TypeError("a class that defines __slots__ without " 
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled 

non mi definisco esplicitamente __slots__ nella mia classe. Qualcosa che ho implicitamente definito? Come posso aggirare questo? Devo definire __getstate__?

Aggiornamento:gnibbler ha scelto un buon esempio. La classe dell'oggetto che sto cercando di sottacere avvolge una presa. (Mi viene in mente ora che) le prese definiscono __slots__ e non __getstate__ per una buona ragione. Presumo che una volta terminato un processo, un altro processo non possa annullare l'operazione e utilizzare la connessione socket del processo precedente. Quindi, mentre sto accettando l'eccellente risposta di Alex Martelli, dovrò seguire una strategia diversa dal pickling per "condividere" il riferimento all'oggetto.

+1

Puoi mostrare del codice dalla classe? Probabilmente non abbiamo bisogno di vedere * tutti * i metodi. –

risposta

26

La classe definendo __slots__ (e non __getstate__) può essere o una classe antenato vostro, o di una classe (o classe base) di un attributo o elemento di tuo, direttamente o indirettamente: essenzialmente, la classe di qualsiasi oggetto in il grafico diretto di riferimenti con l'oggetto come root, poiché il decapaggio deve salvare l'intero grafico.

Una soluzione semplice al tuo dilemma consiste nell'utilizzare il protocollo -1, che significa "il miglior sottaceto di protocollo può utilizzare"; il valore predefinito è un antico protocollo basato su ASCII che impone questa limitazione a __slots__ rispetto a __getstate__. Considerare:

>>> class sic(object): 
... __slots__ = 'a', 'b' 
... 
>>> import pickle 
>>> pickle.dumps(sic(), -1) 
'\x80\x02c__main__\nsic\nq\x00)\x81q\x01.' 
>>> pickle.dumps(sic()) 
Traceback (most recent call last): 
    [snip snip] 
    raise TypeError("a class that defines __slots__ without " 
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled 
>>> 

Come si vede, il protocollo -1 prende il __slots__ nel progresso, mentre il protocollo predefinito dà la stessa eccezione che avete visto.

Problemi con il protocollo -1: produce una stringa/file binario, piuttosto che uno ASCII come il protocollo predefinito; il file pickled risultante non potrebbe essere caricato da versioni sufficientemente antiche di Python. I vantaggi, oltre a quello chiave __slots__, includono risultati più compatti e prestazioni migliori.

Se si è obbligati a utilizzare il protocollo predefinito, è necessario identificare esattamente quale classe ti dà problemi e perché. Possiamo discutere delle strategie se questo è il caso (ma se è possibile utilizzare il protocollo -1, è molto meglio che non vale la pena discuterle ;-) e l'ispezione semplice del codice alla ricerca della classe/oggetto problematico si sta rivelando troppo complicata (ho in mente alcuni trucchi basati sulla deepcopy per ottenere una rappresentazione utilizzabile dell'intero grafico, nel caso ve lo stiate chiedendo).

2

Da PEP 307:

The __getstate__ method should return a picklable value representing the object's state without referencing the object itself. If no __getstate__ method exists, a default implementation is used that returns self.__dict__ .

6

Forse un attributo dell'istanza sta usando __slots__

Per esempio, socket ha __slots__ quindi non può essere in salamoia

È necessario individuare quale attributo sta causando l'errore e scrivi il tuo __getstate__ e __setstate__ per ignorare tale attributo

Problemi correlati