12

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?

15

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
  • 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. – Jon O. 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 6:58
4

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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.