Czy mogę dołączyć wspólny blok kodu w dwóch różnych blokach kodu w trybie Org?

13

Mam org-modeplik zawierający tabelę danych i dwa bloki kodu Pythona, aby wyodrębnić z niej różne podsumowania.

Chciałbym udostępnić niektóre wspólne stałe i funkcje między tymi dwoma blokami kodu. Idealnie zrobiłbym to, dzieląc wspólny kod na osobny blok kodu, który byłby automatycznie uwzględniany i oceniany za każdym razem, gdy oceniany jest jeden z pozostałych dwóch bloków. W gotowej składni wyglądałoby to mniej więcej tak:

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

Chyba mógłbym skorzystać z tej :sessionopcji, ale wolałbym tego nie robić z dwóch powodów. Po pierwsze, tworzy stanowy system, a nie taki, który działa od zera za każdym razem, gdy używam C-c C-cbloku kodu. Po drugie, i w związku z tym muszę teraz pamiętać o ręcznej ocenie wspólnego kodu inicjalizacji za każdym razem, gdy otwieram plik: nie mogę po prostu zaktualizować tabeli danych, przejść do jednego z bloków podsumowań i nacisnąć, C-c C-caby go zaktualizować.

Czy jest na to dobry sposób?

Jon O.
źródło

Odpowiedzi:

16

Możesz to zrobić najłatwiej, używając nowej składni odniesienia org-babel do programowania literackiego. Oto przykład:

* 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
przestarzałe
źródło
Dziękuję Ci. To wygląda świetnie, znacznie lepiej niż moje hackerskie rozwiązanie. Wypróbuję to w ciągu kilku najbliższych dni i sprawdzę, czy mam jakieś problemy.
Jon O.
@JonO. jeśli ta odpowiedź będzie dla Ciebie odpowiednia, to proszę, zaakceptuj ją jako poprawną - dziękuję
wycofano
4

Po zastanowieniu trochę znalazłem częściowe rozwiązanie tego problemu. Używa :session, ale mogę przynajmniej zapewnić, że wspólny kod inicjujący jest zawsze uruchamiany automatycznie przed obliczeniem jednego z pozostałych bloków. „Sztuczka” polega na użyciu fikcyjnej zmiennej nagłówka, która odnosi się do bloku nagłówka, co powoduje, że jest ona oceniana za każdym razem:

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

Teraz mogę zmieniać definicje init_blocki automatycznie ponownie je oceniać za każdym razem, gdy oceniany jest inny blok, który odwołuje się do niego :var dummy=init_block. Działa to dobrze, pod warunkiem, że definicje w init_blocksą idempotentne i bezpaństwowe.

(Zauważ, że przy zmianie bloków Pythona na :sessiontryb musisz usunąć wszelkie returninstrukcje, które są potrzebne w trybie funkcjonalnym, aby zwrócić wartość z bloku).

Jon O.
źródło