19

I have an org-mode file containing a table of data and two Python code blocks to extract different summaries from it.

I would like to share some common constants and functions between these two code blocks. Ideally, I'd do this by factoring out the common code into a separate code block, which would be automatically included and evaluated whenever either of the other two blocks is evaluated. In made-up syntax, it would look something like the following:

#+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

I suppose I could use the :session option, but I would prefer not to, for two reason. First, it sets up a stateful system, rather than one which runs from scratch each time I use C-c C-c on a code block. Second, and relatedly, I now have to remember to manually evaluate the common initialization code each time I open the file: I can't just update the data table, go to one of the summary blocks and hit C-c C-c to update it.

Is there a good way to do this?

2 Answers2

17

You can do this most easily using org-babel's noweb reference syntax for literate programming. Here is an example:

* 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
deprecated
  • 2,775
  • 14
  • 15
  • Thank you. This looks great, much better than my hackish solution. I will try it out in the next few days and see if I have any problems. –  Nov 14 '14 at 23:06
  • @JonO. if this answer works for you then would you please accept it as correct - thanks – deprecated Nov 26 '14 at 06:58
5

After thinking a little more I found a partial solution to this problem. It does use :session, but I can at least ensure that the common initialisation code is always run automatically before evaluating one of the other blocks. The 'trick' is to use a dummy header variable that refers to the header block, causing it to be evaluated each time:

#+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

Now I can change definitions in init_block and have them automatically re-evaluated whenever another block which refers to it using :var dummy=init_block is evaluated. This works well provided that the definitions in init_block are idempotent and stateless.

(Note that when changing Python blocks to :session mode you have to remove any return statements, which are needed in functional mode to return a value from the block).