2009-08-28 15 views
6

(potete leggere this domanda per un certo background)decapaggio garbo-degradanti in Python

mi piacerebbe avere un modo con grazia-degradanti di fare la serializzazione di oggetti in Python.

Durante il decapaggio di un oggetto, chiamiamolo oggetto principale, a volte il Pickler solleva un'eccezione perché non può mettere sottaceti un determinato oggetto secondario dell'oggetto principale. Ad esempio, un errore che ho riscontrato spesso è "non è in grado di decodificare gli oggetti del modulo". Questo perché sto facendo riferimento a un modulo dall'oggetto principale.

So che posso scrivere un po 'di qualcosa per sostituire quel modulo con una facciata che conterrebbe gli attributi del modulo, ma che avrebbe i suoi problemi (1).

Quindi quello che mi piacerebbe è una funzione di decapaggio che sostituisce automaticamente i moduli (e qualsiasi altro oggetto difficile da decapare) con facciate che contengono i loro attributi. Ciò potrebbe non produrre un decapaggio perfetto, ma in molti casi sarebbe sufficiente.

C'è qualcosa del genere? Qualcuno ha un'idea di come affrontarlo?


(1) Un problema potrebbe essere che il modulo potrebbe fare riferimento a altri moduli all'interno di esso.

+1

Java Beans .. Python Pickles .. Mi piacerebbe strozzare i nerd che escono con questo roba cutesy –

risposta

0

Che ne dici di quanto segue, che è un wrapper che è possibile utilizzare per avvolgere alcuni moduli (forse qualsiasi modulo) in qualcosa che è in grado di decollare. È quindi possibile creare una sottoclasse dell'oggetto Pickler per verificare se l'oggetto di destinazione è un modulo e, in tal caso, avvolgerlo. Questo realizza ciò che desideri?

class PickleableModuleWrapper(object): 
    def __init__(self, module): 
     # make a copy of the module's namespace in this instance 
     self.__dict__ = dict(module.__dict__) 
     # remove anything that's going to give us trouble during pickling 
     self.remove_unpickleable_attributes() 

    def remove_unpickleable_attributes(self): 
     for name, value in self.__dict__.items(): 
      try: 
       pickle.dumps(value) 
      except Exception: 
       del self.__dict__[name] 

import pickle 
p = pickle.dumps(PickleableModuleWrapper(pickle)) 
wrapped_mod = pickle.loads(p) 
0

Hmmm, qualcosa del genere?

import sys 

attribList = dir(someobject) 
for attrib in attribList: 
    if(type(attrib) == type(sys)): #is a module 
     #put in a facade, either recursively list the module and do the same thing, or just put in something like str('modulename_module') 
    else: 
     #proceed with normal pickle 

Ovviamente, questo sarebbe andato in un prolungamento della classe salamoia con un metodo discarica reimplementato ...

3

Si può decidere ed attuare come qualsiasi tipo precedentemente unpicklable viene decapato e deserializzato: vedi libreria standard modulo copy_reg (rinominato in copyreg in Python 3. *).

In sostanza, è necessario fornire una funzione che, data un'istanza del tipo, la riduca a una tupla - con lo stesso protocollo del metodo speciale reduce (tranne che il metodo speciale Riduci non accetta argomenti, dal momento che purché sia ​​chiamato direttamente sull'oggetto, mentre la funzione fornita prenderà l'oggetto come unico argomento).

In genere, la tupla restituita contiene 2 elementi: un callable e una tupla di argomenti da passare ad esso. Il callable deve essere registrato come "costruttore sicuro" o avere equivalentemente un attributo __safe_for_unpickling__ con un valore reale. Questi oggetti saranno messi in salamoia, e al momento del disimpegno il callable sarà chiamato con gli argomenti dati e dovrà restituire l'oggetto non selezionato. Ad esempio, supponiamo di voler semplicemente sottoporre a pickle i moduli per nome, in modo che deselezionarli significhi reimportarli (supponiamo per semplicità che non ti interessino i moduli modificati dinamicamente, i pacchetti nidificati, ecc, solo semplici moduli di livello superiore).Poi:

>>> import sys, pickle, copy_reg 
>>> def savemodule(module): 
... return __import__, (module.__name__,) 
... 
>>> copy_reg.pickle(type(sys), savemodule) 
>>> s = pickle.dumps(sys) 
>>> s 
"c__builtin__\n__import__\np0\n(S'sys'\np1\ntp2\nRp3\n." 
>>> z = pickle.loads(s) 
>>> z 
<module 'sys' (built-in)> 

Sto utilizzando il modulo vecchio stile ASCII di salamoia in modo che s, la stringa contenente la salamoia, è facile da esaminare: si incarica deserializzazione di chiamare il built-in funzione di importazione, con la stringa sys come argomento esclusivo. E z dimostra che questo ci restituisce il modulo integrato sys come risultato del non prelievo, come desiderato.

Ora, dovrai rendere le cose un po 'più complesse del solo __import__ (dovrai occuparti di salvare e ripristinare le modifiche dinamiche, navigare in uno spazio dei nomi annidato, ecc.) E quindi dovrai anche chiama copy_reg.constructor (passando come argomento la propria funzione che esegue questo lavoro) prima di copy_reg la funzione di risparmio del modulo che restituisce l'altra funzione (e, se in una corsa separata, anche prima di deselezionare quei sottaceti che hai fatto usando detta funzione). Ma spero che questo semplice caso contribuisca a dimostrare che non c'è davvero niente di tutto ciò che è "intrinsecamente" complicato! -)

+0

@Alex Martelli: Quando uso copy_reg.pickle, qual è lo scopo in cui questa modifica sarà rilevante? Voglio che le persone siano in grado di importare il mio lavoro senza modificare i valori di sistema che potrebbero rovinare il loro programma. –

+0

'copy_reg' è globale. Ma se non sono attualmente i moduli di decapaggio (che è impossibile dalle impostazioni predefinite di sistema), non possono "distruggere il loro programma" per rendere i moduli selezionabili. –

+0

@Alex Martelli: Ma se si fossero imbattuti nello stesso problema e definito il decapaggio dei moduli in un modo diverso, avremmo un problema. Credo nell'essere educato e non cambiare lo stato del sistema. Credo che quando importi un modulo in Python non dovresti preoccuparti di fare confusione con i globali del tuo sistema, e che è importante avere strumenti che ti permettano di evitare questo tipo di "scortesia" nei tuoi moduli. –

Problemi correlati