2012-08-29 8 views
8

Soy bastante nuevo en python, y he estado jugando con él por un tiempo. He estado jugando con la función integrada compile(), junto con marshal y el exec() incorporado. He notado algunas cosas para las que parece que no puedo encontrar las respuestas. Considere el siguiente script:Python exec() de un objeto de código marshaled

#!/usr/bin/python 

def foo(): 
    print "Inside foo()..." 

def main(): 
    print "This is a simple script that should count to 10." 

    for i in range(0, 10): 
     print "This is iteration number", i 

    foo() 

if __name__ == "__main__": 
    main() 

Esto funciona bien cuando se ejecuta a través de algo como:

with open('simple.py', 'r') as f: 
    code = f.read() 
exec code 

Sin embargo, cuando se compila en un objeto de código a través de compile(), serializado a través marshal.dump(), guardar en un archivo y luego leer del archivo, deserializado a través de marshal.load(), y ejecutar con exec(), se equivoca con un NameError que indica que el nombre global foo no está definido.

He visto la salida dada por dir(), y cuando yo import() el código, puedo ver que tiene una definición para foo(). También me he dado cuenta que yo uso con dis.dis() en el objeto de código deserializado (leer a través de marshal.load()), lo único que veo es la LOAD_NAME y CALL_FUNCTION para main() (en lugar de hacer algo así como exec 'import %s' % modname, y luego hacer dis.dis(sys.modules[modname]), lo que le da todo el desmontaje como se esperaba).

¿Tengo la certeza de que hay algún tipo de tabla de búsqueda que import() consulta para obtener estas direcciones? (Para el registro, marqué http://svn.python.org/projects/python/trunk/Lib/py_compile.py y las únicas diferencias que pude ver en el bytecode que se generó a través de py_compile.compile() y el compile() incluido fue el imp.get_magic(), junto con la marca de tiempo de 32 bits). Si tal tabla existe, ¿hay una buena manera de consultarla?

Gracias!

+1

cuando lo que se serializa a través de 'marshal.dump()'? el archivo de texto? – Claudiu

+0

El objeto de código para ese script generado a través de 'compile()'. – user1633448

+0

¿Qué quieres decir? Lo siguiente parece funcionar: con open ('simple.py', 'r') como f: code = f.read() con open ('simple.mash', 'w') como f: marshal.dump (código, f) con ('simple.mash', 'r') abierta como f: código = marshal.load (f) código exec – Dhara

Respuesta

0

Este script ejecuta con éxito su código simple.py 3 veces. ¿Esto aclara algo? ¿O estoy malentendiendo su pregunta?

# from original example 
with open('simple.py', 'r') as f: 
    code = f.read() 
exec(code) 
# compile and run again 
a = compile(code, "simple_compiled_this_file_not_created", "exec") 
exec(a) 
# marshal and unmarshal 
import marshal 
f = open("./marshalfoo.bin", "wb") 
marshal.dump(a,f) 
f.close() 
b = marshal.load(open("./marshalfoo.bin", "rb")) 
exec(b) 
+1

Interesante. Así que pude rastrear mi problema según su código. Parece que si trato de 'exec()' el código desde el interior de una función, falla (por ejemplo, después de ejecutar 'compile()' Llamo a una función que creé llamada 'runme()' que realmente llama a 'exec() 'en el objeto de código resultante). Lo que es aún más interesante es si llamo a 'exec()' desde el mismo ámbito que a 'compile()' y luego invoco 'runme()' para que funcione bien. Así que es seguro un problema de alcance. – user1633448

+1

Para cualquiera que se preocupe, hice que esto funcione como esperaba colocando el código dentro de simple.py dentro de una clase personalizada (lo llamé Simple), y luego en 'if __name__ ==" __main __ "' doing 's = Simple() 'y' s.main() '. Después de eso, el código parece funcionar bien desde cualquier ámbito. – user1633448

Cuestiones relacionadas