Puis-je inclure un bloc de code commun dans deux blocs de code différents en mode Org?

12

J'ai un org-modefichier contenant une table de données et deux blocs de code Python pour en extraire différents résumés.

Je voudrais partager quelques constantes et fonctions communes entre ces deux blocs de code. Idéalement, je le ferais en factorisant le code commun dans un bloc de code séparé, qui serait automatiquement inclus et évalué chaque fois que l'un des deux autres blocs est évalué. Dans une syntaxe inventée, cela ressemblerait à quelque chose comme ceci:

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

Je suppose que je pourrais utiliser l' :sessionoption, mais je préférerais ne pas l'utiliser , pour deux raisons. Tout d'abord, il met en place un système avec état, plutôt qu'un système qui s'exécute à partir de zéro chaque fois que j'utilise C-c C-csur un bloc de code. Deuxièmement, et de manière connexe, je dois maintenant me rappeler d'évaluer manuellement le code d'initialisation commun chaque fois que j'ouvre le fichier: je ne peux pas simplement mettre à jour le tableau de données, aller dans l'un des blocs récapitulatifs et appuyer sur C-c C-cpour le mettre à jour.

Y at-il un bon moyen de le faire?

Jon O.
la source

Réponses:

15

Vous pouvez le faire plus facilement en utilisant la syntaxe de référence noweb d' org-babel pour la programmation lettrée. Voici un exemple:

* 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
obsolète
la source
Je vous remercie. Cela a l'air génial, bien mieux que ma solution hackish. Je vais l'essayer dans les prochains jours et voir si j'ai des problèmes.
Jon O.
@JonO. si cette réponse vous convient, veuillez l'accepter comme correcte - merci
déconseillé
4

Après avoir réfléchi un peu plus, j'ai trouvé une solution partielle à ce problème. Il utilise :session, mais je peux au moins m'assurer que le code d'initialisation commun est toujours exécuté automatiquement avant d'évaluer l'un des autres blocs. L'astuce consiste à utiliser une variable d'en-tête factice qui fait référence au bloc d'en-tête, ce qui entraîne son évaluation à chaque fois:

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

Maintenant, je peux changer les définitions init_blocket les faire réévaluer automatiquement chaque fois qu'un autre bloc qui s'y réfère en utilisant :var dummy=init_blockest évalué. Cela fonctionne bien à condition que les définitions init_blocksoient idempotentes et sans état.

(Notez que lorsque vous changez les blocs Python en :sessionmode, vous devez supprimer toutes les returninstructions, qui sont nécessaires en mode fonctionnel pour renvoyer une valeur du bloc).

Jon O.
la source