Bisakah saya memasukkan blok kode umum dalam dua blok kode berbeda dalam mode Org?

12

Saya memiliki org-modefile yang berisi tabel data dan dua blok kode Python untuk mengekstrak ringkasan berbeda darinya.

Saya ingin berbagi beberapa konstanta umum dan fungsi antara dua blok kode ini. Idealnya, saya akan melakukan ini dengan memasukkan kode umum ke dalam blok kode yang terpisah, yang akan secara otomatis dimasukkan dan dievaluasi setiap kali salah satu dari dua blok lainnya dievaluasi. Dalam sintaksis yang dibuat, itu akan terlihat seperti berikut:

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

Saya kira saya bisa menggunakan :sessionopsi ini, tetapi saya lebih memilih untuk tidak melakukannya, karena dua alasan. Pertama, ini membuat sistem stateful, bukan yang berjalan dari awal setiap kali saya gunakan C-c C-cpada blok kode. Kedua, dan terkait, saya sekarang harus ingat untuk secara manual mengevaluasi kode inisialisasi umum setiap kali saya membuka file: Saya tidak bisa hanya memperbarui tabel data, pergi ke salah satu blok ringkasan dan tekan C-c C-cuntuk memperbaruinya.

Apakah ada cara yang baik untuk melakukan ini?

Jon O.
sumber

Jawaban:

15

Anda dapat melakukan ini dengan paling mudah menggunakan sintaks referensi noweb org-babel untuk pemrograman literasi . Berikut ini sebuah contoh:

* 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
usang
sumber
Terima kasih. Ini terlihat hebat, jauh lebih baik daripada solusi peretasan saya. Saya akan mencobanya dalam beberapa hari ke depan dan melihat apakah saya memiliki masalah.
Jon O.
@JonO. jika jawaban ini cocok untuk Anda, maukah Anda menerimanya sebagai benar - terima kasih
usang
4

Setelah berpikir sedikit lagi saya menemukan solusi parsial untuk masalah ini. Itu memang digunakan :session, tetapi setidaknya saya dapat memastikan bahwa kode inisialisasi umum selalu dijalankan secara otomatis sebelum mengevaluasi salah satu blok lainnya. 'Trik' ini adalah dengan menggunakan variabel header dummy yang merujuk ke blok header, sehingga harus dievaluasi setiap kali:

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

Sekarang saya dapat mengubah definisi init_blockdan meminta mereka secara otomatis dievaluasi ulang setiap kali blok lain yang merujuk padanya menggunakan :var dummy=init_blockdievaluasi. Ini berfungsi dengan baik asalkan definisi di init_blockidempoten dan stateless.

(Perhatikan bahwa saat mengubah blok Python ke :sessionmode, Anda harus menghapus returnpernyataan apa pun , yang diperlukan dalam mode fungsional untuk mengembalikan nilai dari blok).

Jon O.
sumber