Posso incluir um bloco de código comum em dois blocos de código diferentes no modo Org?

12

Eu tenho um org-modearquivo contendo uma tabela de dados e dois blocos de código Python para extrair diferentes resumos dele.

Eu gostaria de compartilhar algumas constantes e funções comuns entre esses dois blocos de código. Idealmente, eu faria isso fatorando o código comum em um bloco de código separado, que seria automaticamente incluído e avaliado sempre que qualquer um dos outros dois blocos fosse avaliado. Na sintaxe inventada, seria algo como o seguinte:

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

Suponho que poderia usar a :sessionopção, mas preferiria não, por dois motivos. Primeiro, ele configura um sistema com estado, em vez de um que roda do zero toda vez que uso C-c C-cem um bloco de código. Segundo, e relacionado, agora tenho que me lembrar de avaliar manualmente o código de inicialização comum cada vez que abro o arquivo: não posso apenas atualizar a tabela de dados, ir a um dos blocos de resumo e pressionar C-c C-cpara atualizá-lo.

Existe uma boa maneira de fazer isso?

Jon O.
fonte

Respostas:

15

Você pode fazer isso mais facilmente usando a sintaxe de referência noweb da org-babel para programação alfabetizada. Aqui está um exemplo:

* 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
descontinuada
fonte
Obrigado. Parece ótimo, muito melhor do que minha solução hackiana. Vou testá-lo nos próximos dias e ver se tenho algum problema.
Jon O.
@JonO. se esta resposta funcionar para você, você poderia aceitá-la como correta - obrigado
reprovado
4

Depois de pensar um pouco mais, encontrei uma solução parcial para esse problema. Ele usa :session, mas posso pelo menos garantir que o código de inicialização comum seja sempre executado automaticamente antes de avaliar um dos outros blocos. O 'truque' é usar uma variável de cabeçalho fictícia que se refere ao bloco de cabeçalho, fazendo com que ela seja avaliada toda 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

Agora eu posso alterar as definições init_blocke tê-las automaticamente reavaliadas sempre que outro bloco que se refere a ele :var dummy=init_blocké avaliado. Isso funciona bem, desde que as definições em init_blocksejam idempotentes e sem estado.

(Observe que ao alterar os blocos Python para o :sessionmodo, você deve remover quaisquer returninstruções necessárias no modo funcional para retornar um valor do bloco).

Jon O.
fonte