Como una continuación a esta pregunta:
Hay una manera fácil de pepinillo una función de python (o de lo contrario serializar su código)?

Me gustaría ver un ejemplo de esta viñeta de el post anterior:

«Si la función de referencias globales (incluyendo los módulos importados, otras funciones, etc) que usted necesita para recoger, usted necesitará serialise estas demasiado, o crearlos en el lado remoto. Mi ejemplo solo la da el proceso remoto del espacio de nombres global.»

Tengo una simple prueba de ir a donde estoy escribiendo una de las funciones de código de bytes en un archivo utilizando el mariscal:

def g(self,blah): 
    print blah

def f(self):
    for i in range(1,5):
        print 'some function f'
        g('some string used by g')

data = marshal.dumps(f.func_code)

file = open('/tmp/f2.txt', 'w')
file.write(data)

Luego, a partir de un fresco de python caso hago:

file = open('/tmp/f2.txt', 'r')
code = marshal.loads(file.read())
func2 = types.FunctionType(code, globals(), "some_func_name");
func2('blah')

Esto se traduce en un:

NameError: global name 'g' is not defined

Esto es independiente de los diferentes enfoques que he hecho a la inclusión de g. He intentado básicamente el mismo enfoque para el envío de g como f, pero f no pueden todavía ver g. ¿Cómo puedo obtener g en el espacio de nombres global, de modo que puede ser utilizado por f en el proceso de recepción?

Alguien también se recomienda buscar en pyro como un ejemplo de cómo hacer esto. Ya he hecho un intento de tratar de entender el código relacionado en la discoteca del proyecto. Tomé su dPickle clase y trató de recrear su disco/tests/test_pickle.py funcionalidad en una aplicación independiente, sin éxito. Mi experimento ha tenido problemas para realizar la función de cálculo de referencias con los basureros de la llamada. De todos modos, tal vez un pyro de exploración es el siguiente.

En resumen, la funcionalidad básica que busco es ser capaz de enviar un método a través del cable y tiene todo lo básico de «espacio de trabajo» métodos de envió con él (como g).

Ejemplo con los cambios de respuesta:

De trabajo function_writer:

import marshal, types

def g(blah): 
    print blah


def f():
    for i in range(1,5):
        print 'some function f'
        g('blah string used by g')


f_data = marshal.dumps(f.func_code)
g_data = marshal.dumps(g.func_code);

f_file = open('/tmp/f.txt', 'w')
f_file.write(f_data)

g_file = open('/tmp/g.txt', 'w')
g_file.write(g_data)

De trabajo function_reader:

import marshal, types

f_file = open('/tmp/f.txt', 'r')
g_file = open('/tmp/g.txt', 'r')

f_code = marshal.loads(f_file.read())
g_code = marshal.loads(g_file.read())

f = types.FunctionType(f_code, globals(), 'f');
g = types.FunctionType(g_code, globals(), 'g');

f()
InformationsquelleAutor Ryan R. | 2012-04-06

5 Comentarios

  1. 4

    He intentado básicamente el mismo enfoque para el envío de g como f, pero f no pueden todavía ver g. ¿Cómo puedo obtener g en el espacio de nombres global, de modo que puede ser utilizado por f en el proceso de recepción?

    De asignar el nombre global g. (Veo que usted está asignando f a func2 en lugar de f. Si usted está haciendo algo parecido con g, entonces está claro por qué f no puede encontrar g. Recuerde que la resolución de nombres que sucede en tiempo de ejecución — g no miró hacia arriba hasta que llame f.)

    Por supuesto, supongo que ya que no se muestra el código que estás usando para ello.

    Podría ser el mejor para crear un diccionario que desea utilizar para el espacio de nombres global para las funciones que está unpickling — una caja de arena. De esa manera todas sus variables globales que será independiente del módulo que usted está haciendo esto. Así que usted podría hacer algo como esto:

    sandbox = {}
    
    with open("functions.pickle", "rb") as funcfile:
        while True:
            try:
                code = marshal.load(funcfile)
            except EOFError:
                 break
            sandbox[code.co_name] = types.FunctionType(code, sandbox, code.co_name)

    En este ejemplo, suponga que usted ha puesto el código de los objetos de todas sus funciones en un archivo, una después de la otra, y cuando la lectura de ellos, puedo obtener el código de nombre del objeto y usarlo como la base para la función del nombre del objeto y el nombre bajo el cual es almacenado en la caja de arena diccionario.

    Dentro de la unpickled funciones, el sandbox diccionario es su globals() por lo que en f(), g obtiene su valor de sandbox["g"]. Para llamar a f entonces sería: sandbox["f"]("blah")

    • Oh wow, no me di cuenta de la referencia asignado hizo la diferencia! Gracias! Publicaremos código de trabajo.
    • Publicado algunas código de mí mismo.
    • Genial, me gusta la caja de arena. Quiero explorar próximo auto registrar todas las funciones a las dependencias automáticamente. Algo así como lo de la discoteca modutil.find_modules método que no. Agradezco la ayuda.
  2. 21

    La nube paquete no esta-sólo ‘pip install nube» y luego:

    import cloud, pickle
    def foo(x): 
        return x*3
    def bar(z): 
        return foo(z)+1
    x = cloud.serialization.cloudpickle.dumps(bar)
    del foo 
    del bar
    f = pickle.loads(x)
    print f(3)  # displays "10"

    En otras palabras, simplemente llame a cloudpickle.dump() o cloudpickle.vertederos() de la misma manera que haría uso de la salmuera.*, luego uso el nativo de pepinillos.load() o pepinillos.cargas() para descongelar.

    Picloud liberado de la ‘nube’ paquete de python bajo la LGPL, y otros proyectos de código abierto ya la están utilizando (en google «cloudpickle.py» para ver un par). La documentación en picloud.com te da una idea de lo poderoso de este código, y por qué ellos tenían un incentivo para poner el esfuerzo en hacer uso general de código del decapado del trabajo: su negocio está construido alrededor de ella. La idea es que si usted tiene cpu_intensive_function() y desea que se ejecute en Amazon EC2 cuadrícula, que acaba de reemplazar:

    cpu_intensive_function(some, args) 

    con:

    cloud.call(cpu_intensive_function, some, args)

    La segunda utiliza cloudpickle a pickle cualquier dependiente de código y de datos, los envía a EC2, la ejecuta y devuelve los resultados a usted cuando usted llame a la nube.resultado(). (Picloud facturas en incrementos de un milisegundo, es barato como diablos, y yo lo uso todo el tiempo para simulaciones de monte carlo y financiera análisis de series de tiempo, cuando tengo cientos de núcleos de CPU para sólo un par de segundos cada uno. No puedo decir suficientes cosas buenas acerca de ella, y yo no trabajo allí).

    • gracias, señor 🙂 he estado luchando con el eneldo por un par de horas, pero la nube funciona recta hacia adelante por lo que creo que debe ser aceptada respuesta
    • Como el original PiCloud SDK de cliente ya no se mantiene, un nuevo proyecto que se inició sólo para mantener la cloudpickle características: github.com/cloudpipe/cloudpickle : pip install cloudpickle
    • su ejemplo no parece guardar construido en función correctamente 🙂
    • Cloudpickle donde se trabajaba el eneldo no pudo correcly reimportación de las dependencias, gracias!
  3. 3

    Usted puede conseguir un mejor manejo de objetos globales mediante la importación de __main__, y el uso de los métodos disponibles en ese módulo. Esto es lo que eneldo para serializar casi nada en python. Básicamente, cuando el eneldo se serializa un interactivamente función definida, se usa un nombre de destrozarlo en __main__ en tanto que la serialización y deserialización de lado que hace __main__ válida del módulo.

    >>> import dill
    >>> 
    >>> def bar(x):
    ...   return foo(x) + x
    ... 
    >>> def foo(x):
    ...   return x**2
    ... 
    >>> bar(3)
    12
    >>> 
    >>> _bar = dill.loads(dill.dumps(bar))
    >>> _bar(3)
    12

    Realidad, eneldo registra los tipos en el pickle del registro, de modo que si usted tiene un poco de negro cuadro de código que utiliza pickle y realmente no se puede editar, a continuación, sólo la importación de eneldo por arte de magia puede hacer que funcione sin monkeypatching de la 3ª parte del código.

    O, si quieres todo el intérprete sesión enviados a través de un «python» imagen», el eneldo también puede hacer eso.

    >>> # continuing from above
    >>> dill.dump_session('foobar.pkl')
    >>>
    >>> ^D
    [email protected]>$ python
    Python 2.7.5 (default, Sep 30 2013, 20:15:49) 
    [GCC 4.2.1 (Apple Inc. build 5566)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import dill
    >>> dill.load_session('foobar.pkl')
    >>> _bar(3)
    12

    Usted puede fácilmente enviar la imagen a través de ssh a otro equipo, y empezar donde lo dejó allí mientras hay compatibilidad de la versión de pepinillo y las habituales advertencias acerca de python cambiar y que las cosas están instalados.

    • pero entonces, si un programa en Python define foo y bar y encurtidos de la barra en un archivo (utilizando el eneldo), y otro programa en Python carga el escabeche archivo en _bar y llamadas _bar(3), que los errores con foo ser indefinido. Por qué no funciona en ese caso?
    • No estoy seguro de ver qué es exactamente lo que están haciendo, tal vez puede dar más detalle (ya sea en una pregunta de la que es propia, o en el github de problemas de la página para dill)?
    • He abierto un nuevo tema aquí: github.com/uqfoundation/dill/issues/176
  4. 2

    Cada módulo tiene su propio globales, no hay universal globales. Podemos «implante» restaurado funciones en algún módulo y utilizar esto como un módulo normal.

    — save —

    import marshal
    def f(x):
        return x + 1
    def g(x):
        return f(x) ** 2
    funcfile = open("functions.pickle", "wb")
    marshal.dump(f.func_code, funcfile)
    marshal.dump(g.func_code, funcfile)
    funcfile.close()

    — restore —

    import marshal
    import types
    open('sandbox.py', 'w').write('')  # create an empty module 'sandbox'
    import sandbox
    with open("functions.pickle", "rb") as funcfile:
        while True:
            try:
                code = marshal.load(funcfile)
            except EOFError:
                 break
            func = types.FunctionType(code, sandbox.__dict__, code.co_name)
            setattr(sandbox, code.co_name, func)   # or sandbox.f = ... if the name is fixed
    assert sandbox.g(3) == 16   # f(3) ** 2
    # it is possible import them from other modules
    from sandbox import g

    Editado:

    Se puede hacer también a la importación de algunos módulos .e.g. «sys» a «sandbox» espacio de nombres desde el exterior:

    sandbox.sys = __import__('sys')

    o el mismo:

    exec 'import sys' in sandbox.__dict__
    assert 'sys' in sandbox, 'Verify imported into sandbox'

    Original del código de trabajo si no lo haces en ipython interactivo, pero en un programa en python o normal interactivo de python!!!

    Ipython utiliza algún espacio de nombres extraños que no es un dict de cualquier módulo de sys.los módulos. Normal de python o cualquier programa principal uso sys.modules['__main__'].__dict__ como globals(). El módulo que se utiliza that_module.__dict__ que también está bien, sólo ipython interactivo es un problema.

    • Gracias! +1, tenía curiosidad acerca de eso también.
    • Su código original wold trabajo si es normal python se utiliza no ipython.
    • No es de importación x ; x.método()’ tipo de escenarios de uso de un problema de los scripts remotos? Como en:stackoverflow.com/questions/10099326/…
  5. 0

    Eneldo (junto con otros pickle variantes, cloudpickle, etc.) parece funcionar cuando la función(s) en escabeche son en el módulo principal, junto con el decapado. Si usted está decapado una función desde otro módulo nombre del módulo tiene que estar presente cuando el unpickling sucede. Me parece no puede encontrar una forma de evitar esta limitación.

Dejar respuesta

Please enter your comment!
Please enter your name here