У каждого языка должен быть преобразователь кода ноутбука, и вот пример одного из них.

Блокноты Юпитер.

Как специалисты по данным, большинство из нас используют их. У них есть свои проблемы, но по сравнению со многими другими доступными решениями ноутбуки обеспечивают отличную среду разработки. Это, конечно, особенно верно, когда ноутбуки действительно часто используются; в области научных вычислений. Ноутбуки просто имеют смысл для тех, кто хочет взаимодействовать с кодом, как это часто требуется для научных вычислений. Тем не менее, ноутбуки также вызывают ряд проблем, связанных с научными вычислениями, и некоторые из них труднее игнорировать, чем другие.

Первая и наиболее очевидная проблема заключается в том, что у ноутбуков есть фундаментальная проблема с воспроизводимостью и состоянием. Я думаю, что это часто преувеличено, так как многие ученые беспокоятся обо всем, что можно сделать неявно, то есть об изменении порядка выполнения, при котором ячейки не будут работать так же, как об удалении ячеек. Я считаю, что это беспокойство имеет смысл, но я также считаю, что средний Ученый способен управлять этими вещами. Однако есть еще одна проблема, которую часто упускают из виду, а именно формат файла IPython. В некотором смысле это часто смягчается возможностью просто выводить файлы Jupyter в файлы Python, но это не совсем так в случае с Julia. Кроме того, независимо от того, станет ли ваш код файлом .jl или файлом .ipynb, вы все равно можете захотеть сохранить вывод, по крайней мере, в том или ином качестве. Сегодня я хотел показать небольшой пакет, который я сделал, который на самом деле извлечен из другого модуля, над которым я работаю, но я подумал, что он может быть хорошим кодом сам по себе. Файлы записной книжки Ipython также занимают много места из-за форматирования данных JSON, а также деталей ядра — вещей, которые не так важны, когда мы знаем, какой язык мы используем, и наш план состоит в том, чтобы теперь быть в чистом коде Julia. , имеет смысл избавиться от всей этой информации в нашем файле.

IpyJL.jl

Пакет, о котором я хотел немного поговорить и, что более важно, поговорить о простоте и полезности IpyJL.jl. Я создал этот проект как простой способ собрать все файлы записной книжки в одну непротиворечивую систему. В Джулии у нас теперь есть записные книжки Pluto, и записные книжки Pluto довольно крутые, но тот факт, что Pluto не может читать записные книжки Jupyter, создает проблему, так как часто коллеги работают с Jupyter и, следовательно, не могут читать в чистом файле JL. Я также думаю, что файлы Pluto.jl как чистой Джулии просто содержат много информации, которая просто не нужна. Например, с какой стати мы сохраняем порядок выполнения по UUID, а затем помечаем каждую ячейку своим UUID? Весь смысл Плутона в том, чтобы держать все клетки в порядке, верно? Так почему же не имеет смысла сохранять ячейки по порядку, а в свою очередь легко читать по порядку построчно?

Я отвлекся, если вы хотите посмотреть мой маленький пакет, он здесь:



Я просто хотел создать пакет, который сделал бы некоторый уровень преобразования между IPython и Julia, что было на удивление легко. На самом деле, файлы IPython — это просто прославленные файлы JSON. Это при том, что для создания этого пакета действительно потребовалось очень мало усилий. Я хотел бы рассказать, как я приступил к созданию этого, таким образом, было бы целесообразно сделать такой конвертер в чем-то вроде R или Python, на что у меня нет времени.

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

mutable struct Cell
        outputs::Any
        ctype::String
        cont::Any
        meta::Dict
        n::Integer
        function Cell(nb_cdict::Dict)
            n = 0
            outputs = ""
            try
                n = nb_cdict["execution_count"]
            catch
                n = 0
            end
            if isnothing(n)
                n = 0
            end
            try
                outputs = nb_cdict["outputs"]
            catch
                outputs = ""
            end
            new(outputs, nb_cdict["cell_type"], nb_cdict["source"],
             nb_cdict["metadata"], n)
    end
end

Здесь try/catches немного уродливы, но в остальном мы выбрасываем KeyError, так что они, безусловно, нужны. Теперь, когда у нас есть структура, нам нужно подумать о функции чтения, а затем о функции записи. Оба из них довольно просты:

"""
## read_ipynb(f::String) -> Vector{Cell}
Reads an IPython notebook into a vector of cells.
### example
read_ipynb("helloworld.ipynb")
"""
function read_ipynb(f::String)
    file = open(f)
    j = JSON.parse(file)
    [Cell(cell) for cell in j["cells"]]
end
"""
## cells_to_string(::Vector{Any}) -> ::String
Converts an array of Cell types into text.
"""
function cells_to_string(cells::Any)
    f = ""
    for cell in cells
        line = ""
        header = string("# ", cell.n, "\n")
        if cell.ctype != "code"
            line = line * string("cellmd", string(cell.n), " = \"\"\"")
            line = line * string(sep(cell.cont)) * "\"\"\"\n"
        else
            line = ""
            line = line * string(sep(cell.cont)) * "\n"
        end
        f = f * header * line
    end
    return(f)
end

По сути, все, что он делает, это объединяет строки вместе на основе данных внутри ячеек, которые мы создаем из словаря. Все это заключено в одну финальную функцию, которая делает и то, и другое, а затем выводит строку в файл.

"""
## ipynbjl(ipynb_path::String, output_path::String)
Reads notebook at **ipynb_path** and then outputs as .jl Julia file to
**output_path**.
### example
ipynbjl("helloworld.ipynb", "helloworld.jl")
"""
function ipynbjl(ipynb_path::String, output_path::String)
    cells = read_ipynb(ipynb_path)
    output = cells_to_string(cells)
    open(output_path, "w") do file
           write(file, output)
    end;
end

Другие языки нуждаются в чем-то подобном…

Я мог видеть, как несколько разных языков извлекают выгоду из чего-то подобного. Конечно, вы можете сохранить как .py из блокнота Jupyter, но это не сохранит вывод. Есть также несколько заметных проблем с моей реализацией, основная из которых заключается в том, что переменные ячейки MD перезаписываются. Я думаю, что что-то подобное может действительно пригодиться, например, в виде автоматических генераторов информационных панелей. Это так, поскольку они могут считывать строки обратно как Markdown и использовать их в качестве контента для страниц и ячеек. Подумайте, как просто было бы что-то подобное, прямое преобразование из IPython в панель мониторинга, позволяющее вам выбирать, какие ячейки сохранить, и напрямую использовать выходные данные ваших блокнотов. Я думаю, что это действительно хорошая идея, и я планирую в конечном итоге реализовать ее, однако до этого момента, безусловно, предстоит проделать большую работу, но я с нетерпением жду будущего такой вещи!

Спасибо, что прочитали этот небольшой обзор пакета, над которым я работал. На данный момент этот крошечный пакет на самом деле является частью чего-то гораздо большего, чем он сам, я все еще работаю над несколькими проектами, которые я начал в прошлом — честно говоря, большая часть вопросов связана с техническим стеком. Моим самым большим недавним соображением было использование веб-сборки и, по сути, написание библиотеки веб-сборки на C++ для обертывания Cxx.jl. Это, конечно, потребует много работы, но возможности всех этих вещей вместе взятых могут быть довольно радикальными. Только подумайте, Джулия эффективно решает две двуязычные задачи одновременно!