Могу ли я включить общий блок кода в два разных блока кода в режиме Org?

12

У меня есть org-modeфайл, содержащий таблицу данных и два блока кода Python для извлечения различных сводок из него.

Я хотел бы поделиться некоторыми общими константами и функциями между этими двумя блоками кода. В идеале я бы сделал это, выделив общий код в отдельный кодовый блок, который будет автоматически включаться и оцениваться всякий раз, когда оценивается любой из двух других блоков. В вымышленном синтаксисе это будет выглядеть примерно так:

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

Я полагаю, я мог бы использовать эту :sessionопцию, но я бы предпочел не делать этого по двум причинам. Во-первых, он устанавливает систему с состоянием, а не систему, которая запускается с нуля каждый раз, когда я использую C-c C-cкодовый блок. Во-вторых, и теперь я должен помнить, что каждый раз, когда открываю файл, вручную оцениваю общий код инициализации: я не могу просто обновить таблицу данных, перейти к одному из сводных блоков и нажать, C-c C-cчтобы обновить его.

Есть ли хороший способ сделать это?

Джон О.
источник

Ответы:

15

Это проще всего сделать, используя синтаксис noweb от org-babel для грамотного программирования. Вот пример:

* 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
Устаревшее
источник
Спасибо. Это выглядит великолепно, намного лучше, чем мое хакерское решение. Я опробую его в ближайшие дни и посмотрю, возникнут ли у меня проблемы.
Джон О.
@JonO. если этот ответ работает для вас, примите, пожалуйста, его как правильный - спасибо
устарел
4

Подумав еще немного, я нашел частичное решение этой проблемы. Он использует :session, но я могу по крайней мере убедиться, что общий код инициализации всегда запускается автоматически, прежде чем оценивать один из других блоков. «Хитрость» состоит в том, чтобы использовать фиктивную переменную заголовка, которая ссылается на блок заголовка, вызывая ее оценку каждый раз:

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

Теперь я могу изменить определения init_blockи сделать так, чтобы они автоматически переоценивались всякий раз, когда оценивается другой блок, который ссылается на него :var dummy=init_block. Это хорошо работает при условии, что определения init_blockявляются идемпотентными и не имеют состояний.

(Обратите внимание, что при переходе блоков Python в :sessionрежим вы должны удалить все returnоператоры, которые необходимы в функциональном режиме для возврата значения из блока).

Джон О.
источник