2013-01-13 12 views
5

Sto usando cPickle per serializzare i dati che vengono utilizzati per la registrazione.cPickle - Ignora roba che non può serializzare invece di generare un'eccezione

Mi piacerebbe essere in grado di lanciare tutto ciò che voglio in un oggetto, quindi serializzarlo. Di solito questo va bene con cPickle, ma si è appena imbattuto in un problema in cui uno degli oggetti che volevo serializzare conteneva una funzione. Ciò ha causato cPickle per generare un'eccezione.

Preferirei che lo cPickle saltasse qualcosa che non può gestire, invece di provocare l'implosione dell'intero processo.

Qual è un buon modo per ottenere questo risultato?

+4

Uh, cattura l'eccezione sollevata? –

+2

La cattura dell'eccezione non sarebbe d'aiuto in quanto il pickling fallirebbe invece di "saltare cose che non può gestire". – user4815162342

risposta

2

Suppongo che tu stia cercando una soluzione best-effort e stai bene se i risultati non voluti non funzionano correttamente.

Per il proprio caso d'uso particolare, è possibile utilizzare register a pickle handler per oggetti funzione. Basta renderlo un gestore fittizio che è abbastanza buono per i tuoi scopi best-effort. Creare un gestore per le funzioni è possibile, è piuttosto complicato. Per evitare di influire su altri codici che decapitano, è probabile che si desideri annullare la registrazione del gestore quando si esce dal codice di registrazione.

Ecco un esempio (senza cancellazione):

import cPickle 
import copy_reg 
from types import FunctionType 

# data to pickle: note that o['x'] is a lambda and they 
# aren't natively picklable (at this time) 
o = {'x': lambda x: x, 'y': 1} 

# shows that o is not natively picklable (because of 
# o['x']) 
try: 
    cPickle.dumps(o) 
except TypeError: 
    print "not natively picklable" 
else: 
    print "was pickled natively" 

# create a mechanisms to turn unpickable functions int 
# stub objects (the string "STUB" in this case) 
def stub_pickler(obj): 
    return stub_unpickler,() 
def stub_unpickler(): 
    return "STUB" 
copy_reg.pickle(
    FunctionType, 
    stub_pickler, stub_unpickler) 

# shows that o is now picklable but o['x'] is restored 
# to the stub object instead of its original lambda 
print cPickle.loads(cPickle.dumps(o)) 

Esso stampa:

not natively picklable 
{'y': 1, 'x': 'STUB'} 
-1

Perché non solo intrappolare l'eccezione?

try: 
    cPickle.dumps(obj) 
except cPickle.PicklingError: 
    pass 

Si può fare questo per mantenere tutto il resto, anche ...

>>> def safe_pickle(L): 
...  result = [] 
...  for target in L: 
...    try: 
...      result.append(cPickle.dumps(target)) 
...    except (cPickle.PicklingError, TypeError): 
...      result.append(None) 
...  return result 
... 
>>> safe_pickle(["A",open('file.txt')]) 
["S'A'\n.", None] 

eccezioni fermati non sono sollevate.

+3

In questo caso, tutto il resto che volevo serializzare non è stato salvato. È necessario saltare il campo specifico che non è in grado di gestire e comunque serializzare tutto il resto. –

+0

@ChrisDutrow Vedi la mia risposta modificata. :) Spero possa essere d'aiuto. –

+5

@frb non funzionerà ancora se un attributo (profondamente annidato) dell'oggetto che si sta tentando di decapare non può essere decapitato. –

0

In alternativa, prova cloudpickle:

>>> import cloudpickle 
>>> squared = lambda x: x ** 2 
>>> pickled_lambda = cloudpickle.dumps(squared) 

>>> import pickle 
>>> new_squared = pickle.loads(pickled_lambda) 
>>> new_squared(2) 
4 

we can pickle that

pip install cloudpickle e vivi i tuoi sogni. Gli stessi sogni vissuti da dask, IPython parallel e PySpark.