2015-05-26 8 views
5

Diciamo che ho una classe come questa: -Pickle Dump per salvare un oggetto all'interno della classe

class MyClass: 
    some object here 
    some other object here 
    def init(self, some parameters): 
    do something 
    def some_other_method(self, param): 
    something else 
    def save(self, path): 
    PICKLE DUMP THIS OBJECT 
    def load(self, path): 
    PICKLE LOAD OBJECT 

io non voglio carico salamoia e discarica come:

obj = MyClass(param) 
pickle.dump(obj, mypath) 

Ma piuttosto in questo modo:

obj.save(mypath) 

Come posso fare questo all'interno della definizione di classe?

+0

Cosa intendi "qualche oggetto qui"? Come stai mettendo un oggetto lì dentro? – BrenBarn

+0

@BrenBarn può essere qualsiasi attributo della classe (non oggetto della stessa classe) – Aditya

+0

@AdityaJoshi: Giusto per essere chiari, 'pickle.dump' non prende un percorso di stringa ... prende un handle di file (cioè' f = open (mypath, 'r') '). Lo stesso per 'pickle.load'. –

risposta

4

È possibile passare self anziché obj. In altre parole:

def save(self, file_handler): 
    pickle.dump(self, file_handler) 

I self indica l'istanza di tale classe. Quindi, ciò che fai in pratica è chiamare pickle.dump e passare l'istanza ad esso insieme all'argomento file_handler.

+1

'dump' prende un handle di file e non un percorso. Mentre questo codice funziona se 'path' è un handle di file, è fuorviante. –

1

Costruiamo una classe A, e provarlo ...

>>> class A(object): 
... x = 1 
... def __init__(self, y): 
...  self.y = y 
... def showme(self): 
...  return self.y + self.x 
... def save(self): 
...  return pickle.dump(self) 
... def load(self, pik): 
...  self.__dict__.update(pickle.loads(pik).__dict__) 
... 
>>> a = A(2) 
>>> a.showme() 
3 
>>> import pickle 
>>>   
>>> a_ = a.save() 
>>> a.y = 5 
>>> a.showme() 
6 
>>> a.load(a_) 
>>> a.y 
2 
>>> a.showme() 
3 
>>> b = A(9) 
>>> b.load(a_) 
>>> b.y 
2 
>>> b.showme() 
3 
>>> b.x = 4 
>>> b.showme() 
6 
>>> b_ = b.save() 
>>> a.load(b_) 
>>> a.x 
4 
>>> a.y 
2 
>>> a.showme() 
6 
>>> 

Tuttavia, dal momento che è stata definita la classe nella __main__, se si dovesse ricominciare da capo la sessione interprete Python ... i vostri sottaceti sarebbe inutile come la classe non esisterebbe più. Questo perché sottaceti di pitone per riferimento. Tuttavia, c'è una soluzione per questo. Se si utilizza dill, è possibile decollare le classi serializzando anche la definizione della classe. Quindi le classi definite in __main__ saranno ancora disponibili in una nuova sessione.

>>> a.showme() 
6 
>>> import dill as pickle 
>>> a.save() 
'\x80\x02cdill.dill\n_create_type\nq\x00(cdill.dill\n_load_type\nq\x01U\x08TypeTypeq\x02\x85q\x03Rq\x04U\x01Aq\x05h\x01U\nObjectTypeq\x06\x85q\x07Rq\x08\x85q\t}q\n(U\x04loadq\x0bcdill.dill\n_create_function\nq\x0c(cdill.dill\n_unmarshal\nq\rU\xaec\x02\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00C\x00\x00\x00s \x00\x00\x00|\x00\x00j\x00\x00j\x01\x00t\x02\x00j\x03\x00|\x01\x00\x83\x01\x00j\x00\x00\x83\x01\x00\x01d\x00\x00S(\x01\x00\x00\x00N(\x04\x00\x00\x00t\x08\x00\x00\x00__dict__t\x06\x00\x00\x00updatet\x06\x00\x00\x00picklet\x05\x00\x00\x00loads(\x02\x00\x00\x00t\x04\x00\x00\x00selft\x03\x00\x00\x00pik(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x04\x00\x00\x00load\t\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\x0e\x85q\x0fRq\x10c__builtin__\n__main__\nh\x0bNN}q\x11tq\x12Rq\x13U\r__slotnames__q\x14]q\x15U\n__module__q\x16U\x08__main__q\x17U\x06showmeq\x18h\x0c(h\rUuc\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\x0e\x00\x00\x00|\x00\x00j\x00\x00|\x00\x00j\x01\x00\x17S(\x01\x00\x00\x00N(\x02\x00\x00\x00t\x01\x00\x00\x00yt\x01\x00\x00\x00x(\x01\x00\x00\x00t\x04\x00\x00\x00self(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x06\x00\x00\x00showme\x05\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\x19\x85q\x1aRq\x1bc__builtin__\n__main__\nh\x18NN}q\x1ctq\x1dRq\x1eU\x01xq\x1fK\x01U\x04saveq h\x0c(h\rU{c\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\r\x00\x00\x00t\x00\x00j\x01\x00|\x00\x00\x83\x01\x00S(\x01\x00\x00\x00N(\x02\x00\x00\x00t\x06\x00\x00\x00picklet\x05\x00\x00\x00dumps(\x01\x00\x00\x00t\x04\x00\x00\x00self(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x04\x00\x00\x00save\x07\x00\x00\x00s\x02\x00\x00\x00\x00\x01q!\x85q"Rq#c__builtin__\n__main__\nh NN}q$tq%Rq&U\x07__doc__q\'NU\x08__init__q(h\x0c(h\rUuc\x02\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\r\x00\x00\x00|\x01\x00|\x00\x00_\x00\x00d\x00\x00S(\x01\x00\x00\x00N(\x01\x00\x00\x00t\x01\x00\x00\x00y(\x02\x00\x00\x00t\x04\x00\x00\x00selfR\x00\x00\x00\x00(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x08\x00\x00\x00__init__\x03\x00\x00\x00s\x02\x00\x00\x00\x00\x01q)\x85q*Rq+c__builtin__\n__main__\nh(NN}q,tq-Rq.utq/Rq0)\x81q1}q2(U\x01yq3K\x02h\x1fK\x04ub.' 
>>> 

Poi abbiamo chiudere la sessione, e riavviare. Incollare nella stringa dall'alto. (Sì, ho potuto lavorare con un handle di file, invece, ma ti faccio vedere che più tardi ...)

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill as pickle 
>>> 
>>> a = '\x80\x02cdill.dill\n_create_type\nq\x00(cdill.dill\n_load_type\nq\x01U\x08TypeTypeq\x02\x85q\x03Rq\x04U\x01Aq\x05h\x01U\nObjectTypeq\x06\x85q\x07Rq\x08\x85q\t}q\n(U\x04loadq\x0bcdill.dill\n_create_function\nq\x0c(cdill.dill\n_unmarshal\nq\rU\xaec\x02\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00C\x00\x00\x00s \x00\x00\x00|\x00\x00j\x00\x00j\x01\x00t\x02\x00j\x03\x00|\x01\x00\x83\x01\x00j\x00\x00\x83\x01\x00\x01d\x00\x00S(\x01\x00\x00\x00N(\x04\x00\x00\x00t\x08\x00\x00\x00__dict__t\x06\x00\x00\x00updatet\x06\x00\x00\x00picklet\x05\x00\x00\x00loads(\x02\x00\x00\x00t\x04\x00\x00\x00selft\x03\x00\x00\x00pik(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x04\x00\x00\x00load\t\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\x0e\x85q\x0fRq\x10c__builtin__\n__main__\nh\x0bNN}q\x11tq\x12Rq\x13U\r__slotnames__q\x14]q\x15U\n__module__q\x16U\x08__main__q\x17U\x06showmeq\x18h\x0c(h\rUuc\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\x0e\x00\x00\x00|\x00\x00j\x00\x00|\x00\x00j\x01\x00\x17S(\x01\x00\x00\x00N(\x02\x00\x00\x00t\x01\x00\x00\x00yt\x01\x00\x00\x00x(\x01\x00\x00\x00t\x04\x00\x00\x00self(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x06\x00\x00\x00showme\x05\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\x19\x85q\x1aRq\x1bc__builtin__\n__main__\nh\x18NN}q\x1ctq\x1dRq\x1eU\x01xq\x1fK\x01U\x04saveq h\x0c(h\rU{c\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\r\x00\x00\x00t\x00\x00j\x01\x00|\x00\x00\x83\x01\x00S(\x01\x00\x00\x00N(\x02\x00\x00\x00t\x06\x00\x00\x00picklet\x05\x00\x00\x00dumps(\x01\x00\x00\x00t\x04\x00\x00\x00self(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x04\x00\x00\x00save\x07\x00\x00\x00s\x02\x00\x00\x00\x00\x01q!\x85q"Rq#c__builtin__\n__main__\nh NN}q$tq%Rq&U\x07__doc__q\'NU\x08__init__q(h\x0c(h\rUuc\x02\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\r\x00\x00\x00|\x01\x00|\x00\x00_\x00\x00d\x00\x00S(\x01\x00\x00\x00N(\x01\x00\x00\x00t\x01\x00\x00\x00y(\x02\x00\x00\x00t\x04\x00\x00\x00selfR\x00\x00\x00\x00(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x08\x00\x00\x00__init__\x03\x00\x00\x00s\x02\x00\x00\x00\x00\x01q)\x85q*Rq+c__builtin__\n__main__\nh(NN}q,tq-Rq.utq/Rq0)\x81q1}q2(U\x01yq3K\x02h\x1fK\x04ub.' 
>>> 
>>> pickle.loads(a) 
<__main__.A object at 0x105691c50> 
>>> b = _ 
>>> 
>>> b.x 
4 
>>> b.showme() 
6 
>>> A = b.__class__ 
>>> c = A(2) 
>>> c.x 
1 
>>> c.showme() 
3 

Incredibilmente, la classe è ricostruito nel __main__ dall'interno dell'istanza in salamoia. Ok, quindi ora, andiamo a cambiare i metodi di classe per usare un nuovo save e load che funziona con i file anziché con le stringhe.

>>> def save(self, path): 
... with open(path, 'w') as f:   
...  pickle.dump(self, f) 
... 
>>> def load(self, path): 
... with open(path, 'r') as f: 
...  self.__dict__.update(pickle.load(f).__dict__) 
... 
>>> A.save = save 
>>> A.load = load 
>>> 
>>> c.save('foo') 
>>> 

Quindi si chiude la sessione e si riavvia. Poiché non disponiamo di una versione di A, dobbiamo utilizzare il metodo load direttamente da pickle (in realtà, dill in questo caso).

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill as pickle 
>>> with open('foo', 'r') as f: 
... a = pickle.load(f) 
... 
>>> a 
<__main__.A object at 0x1028c0b10> 
>>> a.x 
1 
>>> a.showme() 
3 
>>> a.y = 6 
>>> a.showme() 
7 
>>> a.load('foo') 
>>> a.y  
2 
>>> a.showme() 
3 
>>> 

Ci potrebbe essere un modo migliore, o più specifiche, che si vorrebbe caricare lo stato del l'istanza della classe, piuttosto che l'aggiornamento del __dict__. Fare questo non funzionerà in tutti i casi, ed è probabilmente meglio personalizzare per la tua classe. Se fosse me, tuttavia, non avrei i metodi save e load nella classe, ma utilizzerei direttamente i metodi forniti dal serializzatore. Puoi vedere sopra quanto è scomodo/ridondante usare il metodo load all'interno della classe.