¿Puedo incluir un bloque de código común en dos bloques de código diferentes en modo Org?

12

Tengo un org-modearchivo que contiene una tabla de datos y dos bloques de código Python para extraer diferentes resúmenes de él.

Me gustaría compartir algunas constantes y funciones comunes entre estos dos bloques de código. Idealmente, haría esto factorizando el código común en un bloque de código separado, que se incluiría y evaluaría automáticamente cada vez que se evalúe cualquiera de los otros dos bloques. En una sintaxis inventada, se vería algo así:

#+NAME: init_block
#+BEGIN_SRC python
  ... common constants and functions here ...
#+END_SRC

#+NAME: summary_1
#+BEGIN_SRC python :prepend init_block
  ... data-processing code depending on init code goes here ...
#+END_SRC

#+NAME: summary_2
#+BEGIN_SRC python :prepend init_block
  ... more processing which also depends on init code ...
#+END_SRC

Supongo que podría usar la :sessionopción, pero preferiría no hacerlo, por dos razones. Primero, configura un sistema con estado, en lugar de uno que se ejecuta desde cero cada vez que lo uso C-c C-cen un bloque de código. En segundo lugar, y de manera relacionada, ahora tengo que recordar evaluar manualmente el código de inicialización común cada vez que abro el archivo: no puedo simplemente actualizar la tabla de datos, ir a uno de los bloques de resumen y presionar C-c C-cpara actualizarlo.

¿Existe una forma correcta de hacer esto?

Jon O.
fuente

Respuestas:

15

Puede hacerlo más fácilmente utilizando la sintaxis de referencia noweb de org-babel para la programación alfabetizada. Aquí hay un ejemplo:

* Initialization block containing function definition
#+NAME: init_block
#+BEGIN_SRC python
  constant=19
  def some_function(x):
    return constant * x
#+END_SRC

* Call the function on an integer
#+BEGIN_SRC python :noweb yes 
  <<init_block>>
  return some_function(13)
#+END_SRC

#+RESULTS:
: 247

* Call the function on a string
:PROPERTIES:
:noweb:    yes
:END:

#+BEGIN_SRC python
  <<init_block>>
  return some_function('abc')
#+END_SRC

#+RESULTS:
: abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
obsoleto
fuente
Gracias. Esto se ve muy bien, mucho mejor que mi solución pirata. Lo probaré en los próximos días y veré si tengo algún problema.
Jon O.
@JonO. Si esta respuesta funciona para usted, ¿podría aceptarla como correcta? Gracias
desuso el
4

Después de pensar un poco más, encontré una solución parcial a este problema. Sí usa :session, pero al menos puedo asegurarme de que el código de inicialización común siempre se ejecute automáticamente antes de evaluar uno de los otros bloques. El 'truco' es usar una variable de encabezado ficticio que se refiera al bloque de encabezado, haciendo que se evalúe cada vez:

#+NAME: init_block
#+BEGIN_SRC python :session t
  constant=19
  def some_function(x):
    return constant * x
#+END_SRC

#+BEGIN_SRC python :session t :var dummy=init_block
some_function(13)
#+END_SRC

#+RESULTS:
: 247

Ahora puedo cambiar las definiciones init_blocky hacer que se vuelvan a evaluar automáticamente cada vez que se evalúe otro bloque que se refiera a él usando :var dummy=init_block. Esto funciona bien siempre que las definiciones init_blocksean idempotentes y sin estado.

(Tenga en cuenta que al cambiar los bloques de Python al :sessionmodo, debe eliminar todas las returndeclaraciones, que son necesarias en el modo funcional para devolver un valor del bloque).

Jon O.
fuente