2010-04-13 7 views
5

¿Hay alguna manera de obtener una definición de clase?Decapado de una definición de clase

Lo que me gustaría hacer es resumir la definición (que puede crearse dinámicamente) y luego enviarla a través de una conexión TCP para que se pueda crear una instancia en el otro extremo.

Entiendo que pueden existir dependencias, como módulos y variables globales de las que depende la clase. Me gustaría agrupar estos en el proceso de decapado también, pero no me preocupa detectar automáticamente las dependencias porque está bien si el usuario tiene la responsabilidad de especificarlas.

+0

yo encontramos este cuales Pickles todo el estado intérprete: http://dev.pocoo.org/hg/sandbox/file/tip/pshell.py Las definiciones de clase también parecen ser guardadas en escabeche ... – Giorgio

Respuesta

2

Alas, no directamente. Puede enviar el formato de cadena de la declaración class, o un formulario de código de bytes, y "rehidratarlo" con un exec en el extremo receptor.

+0

¿Se refiere simplemente a enviar los archivos .py o .pyc que contienen la declaración de clase? – Giorgio

+1

@Giorgio, no es necesario que envíe _all_ del archivo '.py' o' .pyc', solo el origen de la clase (identificado por http://docs.python.org/library/inspect) .html? # inspect.getsource) o su forma 'compile'd. –

1

La documentación hace un buen trabajo al explicar qué se puede y no se puede escatimar, y por qué.

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

Básicamente, si la clase o módulo es importable por su nombre cuando se unpickled, que debería funcionar, a menos que piense en cambiar su definición de clase entre ahora y cuando se unpickle. En la siguiente definición de clase, solo se escalarán el nombre de la clase "Prueba" y el nombre del método "mymethod". Si desglosa la definición de la clase, entonces cambia la definición para que attr sea un valor diferente, y mymethod haga algo completamente diferente, el pickle recogerá la nueva definición.

class Test(object): 
    attr = 5 

    def mymethod(self, arg): 
     return arg 
1

Si utiliza dill, que le permite tratar __main__ como si se tratara de un módulo de Python (en su mayor parte). Por lo tanto, puede serializar clases definidas interactivamente, y similares. dill también (de manera predeterminada) puede transportar la definición de clase como parte del pickle.

>>> class MyTest(object): 
... def foo(self, x): 
...  return self.x * x 
... x = 4 
... 
>>> f = MyTest() 
>>> import dill 
>>> 
>>> with open('test.pkl', 'wb') as s: 
... dill.dump(f, s) 
... 
>>> 

A continuación, apague el intérprete, y enviar el archivo test.pkl a través de TCP. En su máquina remota, ahora puede obtener la instancia de clase.

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 
>>>    

¿Pero cómo obtener la definición de clase? Entonces esto no es exactamente lo que querías. El siguiente es, sin embargo.

>>> 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) 
... 
>>> 

Luego de enviar el archivo ... puede obtener la definición de la clase.

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 

Por lo tanto, dentro de dill, hay dill.source, y que cuenta con métodos que pueden detectar dependencias de funciones y clases, y las toman junto con el pepinillo (en su mayor 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 

Así que eso no es "perfecto" (o tal vez no lo que se espera) ... pero sí serializar el código de un método integrado de forma dinámica y es dependencias. Simplemente no obtienes el resto de la clase, pero el resto de la clase no es necesario en este caso.

Si quisiera obtener todo, podría simplemente recuperar toda la sesión.

>>> 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') 
>>> 

Luego en la máquina remota ...

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 

Por último, si desea que el transporte que vayan a "hacer" para que de forma transparente, se puede usar pathos.pp o ppft, que proporciona la capacidad de enviar objetos a un segundo servidor pitón (en una máquina remota) o pitón proceso. Usan dill debajo del capó, y simplemente pasan el código a través del cable.

>>> 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] 

El argumento servers es opcional, y aquí se acaba de conectar a la máquina local en el puerto 1234 ... pero si se utiliza el nombre de la máquina remota y el puerto en lugar (o además), se le disparar a la máquina remota - "sin esfuerzo".

Get dill, pathos y ppft aquí: https://github.com/uqfoundation

Cuestiones relacionadas