¿Cómo lograr que Python escriba el código de una función que tiene en la memoria?

Cuando paso las opciones en el progtwig (un experimento de biología computacional) usualmente las paso a través de un archivo .py.
Así que tengo este archivo .py que se lee como:

starting_length=9 starting_cell_size=1000 LengthofExperiments=5000000 

Luego ejecuto el archivo y obtengo los datos. Dado que el progtwig está todo 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 experimento a experimento.

Pero lo que no puedo hacer es escribir la función automáticamente. En resumen, no sé cómo generalizar la función de opciones de escritura para seguir escribiendo las opciones, si una de las opciones es una función. Por supuesto, podría copiar el archivo original, pero esto es poco elegante, ineficiente (porque contiene muchas opciones adicionales que no se están utilizando) y, en general, no resuelve la pregunta.

    ¿Cómo hacer que Python anote el código de una función, ya que anota el valor de una variable?

     vinko @ mithril $ más a.py
    
     def foo (a):
       imprimir un
    
     vinko @ mithril $ más b.py
    
     importar un
     inspeccionar importación
    
     a.foo (89)
     imprimir inspect.getsource (a.foo)
    
     vinko @ mithril $ python b.py
     89
     def foo (a):
       imprimir un
    
    

    También puede considerar otros medios de persistencia de datos. En mi propia investigación (astronomía), he estado experimentando con dos medios diferentes de almacenamiento de scripts para la reproducibilidad. El primero es tenerlos exclusivamente dentro de un repository de subversión, y luego hacer que el script de envío del trabajo los confirme automáticamente. Por ejemplo, si solo quisieras hacer esto en bash:

     alias run_py='svn ci -m "Commit before running"; python2.5 $*' 

    y dentro de la secuencia de comandos, si la salida tiene el prefijo actual del número de revisión de subversión para ese archivo, tendrá un registro de cada secuencia de comandos que se ejecutó y cuál fue la entrada. Podrías sacar esto de la subversión cuando 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 la entrada XML-RPC y viene con enlaces Python. (Se puede instalar localmente y tiene soporte para responder y actualizar las pastas existentes).

    Pero, si está buscando una cantidad relativamente pequeña de código para incluir, la solución de Vinko que usa inspeccion debería funcionar bastante bien. Doug Hellman cubrió el módulo de inspect en su serie Módulo de la Semana en Python . Podría 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 

    Probablemente esto 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 las lambdas.

    ¿Estás preguntando por 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?

    Si bien es posible hacer lo que pidas (como lo ha demostrado Vinko), yo diría que es más fácil compartir el código . Coloque a pippo y sus amigos en un submódulo al que puedan acceder ambos progtwigs.

    En lugar de sumergirse en el tema de los desensambladores y los códigos de bytes (por ejemplo, inspeccionar ), ¿por qué no guarda la fuente de Python generada en un módulo ( archivo.py ) y luego la importa?

    Yo 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 mira en los módulos marshal y pickle .