2010-04-13 14 views
5

C'è un modo per declassare una definizione di classe?Decapaggio di una definizione di classe

Quello che mi piacerebbe fare è decollare la definizione (che può essere creata dinamicamente), e quindi inviarla su una connessione TCP in modo che un'istanza possa essere creata dall'altra parte.

Capisco che potrebbero esserci delle dipendenze, come moduli e variabili globali su cui si basa la classe. Mi piacerebbe raggrupparli anche nel processo di pickling, ma non mi preoccupo di rilevare automaticamente le dipendenze perché va bene se l'onere è sull'utente di specificarle.

+0

ho trovato questo che Pickles l'intero stato interprete: http://dev.pocoo.org/hg/sandbox/file/tip/pshell.py Anche le definizioni di classe sembrano essere decapate ... – Giorgio

risposta

2

Ahimè, non direttamente. È possibile inviare il modulo stringa dell'istruzione class o un modulo bytecode e "reidratarlo" con un exec sul lato ricevente.

+0

Ti riferisci solo a inviare i file .py o .pyc che contengono l'istruzione della classe? – Giorgio

+1

@Giorgio, non devi necessariamente inviare _all_ del file '.py' o' .pyc', solo l'origine della classe stessa (come identificato da http://docs.python.org/library/inspect .html? # inspect.getsource) o il suo 'modulo di compilazione'd. –

1

La documentazione fa un buon lavoro di spiegazione di ciò che può e non può essere decapato, e perché è così.

http://docs.python.org/library/pickle.html#what-can-be-pickled-and-unpickled

In sostanza, se la classe o il modulo è importato con nome quando viene poterlo più deserializzare, dovrebbe funzionare, a meno che non si ha intenzione di cambiare la vostra definizione della classe tra oggi e quando si deserializzare esso. Nella seguente definizione di classe, solo il nome della classe "Test" e il nome del metodo "mymethod" saranno decapitati. Se si sottrae la definizione della classe, quindi modificare la definizione in modo che attr sia un valore diverso e mymethod faccia qualcosa di completamente diverso, pickle riprenderà la nuova definizione.

class Test(object): 
    attr = 5 

    def mymethod(self, arg): 
     return arg 
1

Se si utilizza dill, vi permette di trattare __main__ come se si trattasse di un modulo python (per la maggior parte). Quindi, è possibile serializzare classi definite in modo interattivo e simili. dill inoltre (per impostazione predefinita) può trasportare la definizione della classe come parte del pickle.

Quindi chiudere l'interprete e inviare il file test.pkl su TCP. Sulla tua macchina remota, ora puoi ottenere l'istanza della classe.

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 
>>> with open('test.pkl', 'rb') as s: 
... f = dill.load(s) 
... 
>>> f 
<__main__.MyTest object at 0x1069348d0> 
>>> f.x 
4 
>>> f.foo(2) 
8 
>>>    

Ma come ottenere la definizione della classe? Quindi questo non è esattamente quello che volevi. Quello che segue è, tuttavia.

>>> class MyTest2(object): 
... def bar(self, x): 
...  return x*x + self.x 
... x = 1 
... 
>>> import dill 
>>> with open('test2.pkl', 'wb') as s: 
... dill.dump(MyTest2, s) 
... 
>>> 

Quindi dopo aver inviato il file ... è possibile ottenere la definizione della classe.

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 
>>> with open('test2.pkl', 'rb') as s: 
... MyTest2 = dill.load(s) 
... 
>>> print dill.source.getsource(MyTest2) 
class MyTest2(object): 
    def bar(self, x): 
    return x*x + self.x 
    x = 1 

>>> f = MyTest2() 
>>> f.x 
1 
>>> f.bar(4) 
17 

Quindi, entro dill, c'è dill.source, e che dispone di metodi in grado di rilevare le dipendenze di funzioni e classi, e li prendere con la salamoia (per la maggior parte).

>>> def foo(x): 
... return x*x 
... 
>>> class Bar(object): 
... def zap(self, x): 
...  return foo(x) * self.x 
... x = 3 
... 
>>> print dill.source.importable(Bar.zap, source=True) 
def foo(x): 
    return x*x 
def zap(self, x): 
    return foo(x) * self.x 

modo che non è "perfetta" (o forse non quello che ci si aspetta) ... ma lo fa serializzare il codice per un metodo incorporato in modo dinamico ed è dipendenze. Non si ottiene il resto della classe, ma il resto della classe non è necessario in questo caso.

Se si desidera ottenere tutto, si potrebbe semplicemente mettere sottosopra l'intera sessione.

>>> import dill 
>>> def foo(x): 
... return x*x 
... 
>>> class Blah(object): 
... def bar(self, x): 
...  self.x = (lambda x:foo(x)+self.x)(x) 
... x = 2 
... 
>>> b = Blah() 
>>> b.x 
2 
>>> b.bar(3) 
>>> b.x 
11 
>>> dill.dump_session('foo.pkl') 
>>> 

Quindi sul dispositivo remoto ...

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 
>>> dill.load_session('foo.pkl') 
>>> b.x 
11 
>>> b.bar(2) 
>>> b.x 
15 
>>> foo(3) 
9 

Infine, se si desidera che il trasporto per essere "fatto" per voi in modo trasparente, è possibile utilizzare pathos.pp o ppft, che forniscono la possibilità di spedire gli oggetti ad un secondo server python (su una macchina remota) o pitone processi. Usano dill sotto il cofano e passano il codice attraverso il cavo.

>>> class More(object): 
... def squared(self, x): 
...  return x*x 
... 
>>> import pathos 
>>> 
>>> p = pathos.pp.ParallelPythonPool(servers=('localhost,1234',)) 
>>> 
>>> m = More() 
>>> p.map(m.squared, range(5)) 
[0, 1, 4, 9, 16] 

L'argomento servers è facoltativo, e qui è solo la connessione alla macchina locale sulla porta 1234 ... ma se si utilizza il nome del computer remoto e la porta, invece (o oltre), potrai sparare al macchina remota - "senza sforzo".

Get dill, pathos, e ppft qui: https://github.com/uqfoundation

Problemi correlati