udacity - ¿Cómo logras que Python escriba el código de una función que tiene en la memoria?
tensorflow (5)
Cuando paso las opciones en el programa (un experimento de biología computacional) generalmente las paso por un archivo .py.
Así que tengo este archivo .py que dice así:
starting_length=9
starting_cell_size=1000
LengthofExperiments=5000000
Luego ejecuto el archivo y obtengo la información. Como el programa está en mi máquina y nadie más tiene acceso a él, es seguro de una manera trivial.
También puedo escribir un archivo similar muy fácilmente:
def writeoptions(directory):
options=""
options+="starting_length=%s%s"%(starting_length,os.linesep)
options+="starting_cell_size=%s%s"%(starting_cell_size,os.linesep)
options+="LengthofExperiments=%s%s"%(LengthofExperiments,os.linesep)
...
open("%s%soptions.py"%(directory,os.sep),''w'').write(options)
Quiero pasar una función como uno de los parámetros:
starting_length=9
starting_cell_size=1000
LengthofExperiments=5000000
def pippo(a,b):
return a+b
functionoperator=pippo
Y, por supuesto, en el experimento real, la función pippo será mucho más compleja. Y diferente de experimentar para experimentar.
Pero lo que no puedo hacer es escribir la función automáticamente. En resumen, no sé cómo generalizar la función writeoptions para seguir escribiendo las opciones, si una de las opciones es una función. Por supuesto, pude copiar el archivo original, pero esto es poco elegante, ineficiente (porque contiene muchas opciones adicionales que no se están usando) y generalmente no resuelve la pregunta.
¿Cómo logras que python escriba el código de una función, ya que anota el valor de una variable?
¿Estás preguntando sobre esto?
def writeoptions(directory):
options=""
options+="starting_length=%s%s"%(starting_length,os.linesep)
options+="starting_cell_size=%s%s"%(starting_cell_size,os.linesep)
options+="LengthofExperiments=%s%s"%(LengthofExperiments,os.linesep)
options+="def pippo(a,b):%s" % ( os.linesep, )
options+=" ''''''Some version of pippo''''''%s" % ( os.linesep, )
options+=" return 2*a+b%s" % ( os.linesep, )
open("%s%soptions.py"%(directory,os.sep),''w'').write(options)
¿O algo mas?
En lugar de sumergirse en el tema de desensambladores y códigos de bytes (por ejemplo, inspeccionar ), ¿por qué no guarda la fuente de Python generada en un módulo ( archivo.py ) y luego lo importa?
Sugeriría buscar una forma más estándar de manejar lo que usted llama opciones . Por ejemplo, puede usar el módulo JSON y guardar o restaurar sus datos. O mire en los módulos de mariscal y encurtido .
Si bien es posible hacer lo que pides (como ha demostrado Vinko), yo diría que es más limpio compartir el código . Coloque pippo
y sus amigos en un submódulo al que puedan acceder ambos programas.
También podría considerar algún otro medio de persistencia de datos. En mi propia investigación (astronomía), he estado experimentando con dos maneras diferentes de almacenar guiones para reproducibilidad. El primero es tenerlos exclusivamente dentro de un repositorio de subversión, y luego hacer que el script de envío de trabajos los envíe automáticamente. Por ejemplo, si solo quieres hacer esto en bash:
alias run_py=''svn ci -m "Commit before running"; python2.5 $*''
y dentro de la secuencia de comandos, haga que la salida prefijada por el número de revisión de subversión actual para ese archivo, tenga un registro de cada secuencia de comandos que se ejecutó y cuál fue la entrada. Podría sacar esto de la subversión según sea necesario.
Otro medio, sustancialmente menos completo, para rastrear la entrada a una función podría ser a través de algo como LodgeIt , un pastebin que acepta entrada XML-RPC y viene con enlaces de Python. (Se puede instalar localmente y tiene soporte para responder y actualizar las existentes).
Pero, si está buscando una cantidad relativamente pequeña de código para ser incluido, la solución de Vinko que utiliza inspeccionar debería funcionar bastante bien. Doug Hellman cubrió el módulo de inspect
en su serie Python Module of the Week . Puede crear un decorador que examine cada opción y argumento y luego lo imprima según corresponda ( inspect.getargspec
para obtener los nombres de los argumentos).
import inspect
from functools import wraps
def option_printer(func):
@wraps(func)
def run_func(*args, **kwargs):
for name, arg in zip(inspect.getargspec(func)[0], args) /
+ sorted(kwargs.items()):
if isinstance(arg, types.FunctionType):
print "Function argument ''%s'' named ''%s'':/n" % (name, func.func_name)
print inspect.getsource(func)
else:
print "%s: %s" % (name, arg)
return func(*args, **kwargs)
return run_func
Esto probablemente podría hacerse un poco más elegante, pero en mis pruebas funciona para conjuntos simples de argumentos y variables. Además, podría tener algunos problemas con lambdas.
vinko@mithril$ more a.py def foo(a): print a vinko@mithril$ more b.py import a import inspect a.foo(89) print inspect.getsource(a.foo) vinko@mithril$ python b.py 89 def foo(a): print a