如何将 Julia 代码中的所有全局变量保存到文件中?

How to save all global variables from a Julia code into a file?

我正在尝试将 Julia 代码中的所有全局变量保存到一个文件中,这样它就可以在单独的 Julia 代码中读取,并且相同的值将分配给同名的全局变量。我知道像字典这样的数据结构可以很容易地保存到 JSON/JLD2/.. 文件等中,但这将非常麻烦并且需要大量手动工作才能将变量保存到字典中并在其中读取它另一个文件并再次分配值(或者有什么快速的方法可以做到这一点?)。似乎 Julia 中的元编程可能会为我提供一个解决方案,但我不熟悉它。完成此类任务的最佳解决方案是什么?

这里假设所有这些变量都是浮点数、数组、字典等“常规”数据结构,不包括插值函数、图像等。并且非常优选这些参数可以保存为流行的文件类型,如 txt/csv/json.

例如,在 Julia 文件中定义了以下变量:

x = 1
y = 2
z = [x,y,[x,y]]
str = "Hello World"
tup = (2,3,(4,5))
dict = Dict([("A", 1), ("B", 2)])

那么如何将信息保存到一个文件中,以便在另一个 Julia 文件中可以立即为同名变量分配相同的值?

例如,如果可以将变量转换为 Dict("x"=>1, "y"=>2, "z"=>[1,2,[1,2]]) 形式的字典,这样它就可以保存在 JSON 文件中,这对我来说是可以接受的,前提是可以将字典的键转换为变量名称,并将它们的值转换为另一个 Julia 文件中的变量值。

编辑:我使用以下方法作为临时解决方案:

# The definitions of variables are declared as a string
variables_definition = """
x = 1
y = 2
z = [x,y,[x,y]]
str = "Hello World"
tup = (2,3,(4,5))
dict = Dict([("A", 1), ("B", 2)])
"""
# Writing the string into another Julia file
open("variables.jl","w") do f
    print(f, variables_definition)
end

# Read the Julia file to import the variables
include("variables.jl")

但是是否有更优雅的解决方案不需要将定义显式声明为字符串?

这个功能实际上是由 JLD2 提供的,尽管它不是推荐的做事方式。来自 JLD2 docs:

For interactive use you can save all variables in the current module's global scope using @save filename. More permanent code should prefer the explicit form to avoid saving unwanted variables.

使用 JLD2,您的示例将变为:

using JLD2
# Definitions of variables
x = 1
y = 2
z = [x,y,[x,y]]
str = "Hello World"
tup = (2,3,(4,5))
dict = Dict([("A", 1), ("B", 2)])

@save "variables.jld2"

在文件中使用变量

using JLD2

@load "variables.jld2"

实现的代码可以在当前模块上找到here. It works by calling the names (docs)函数,然后过滤结果找到can/should保存的变量。当 Julia 启动时,当前模块是 Main 所以要在 REPL 中尝试这个你可以 运行 names(Main).

这是一个原理证明,它使用 names 为 JSON 创建一个类似于 @save 宏的函数:

using JSON

function globals_to_json(m)
    json_compat = Dict{String, Any}()
    for name in names(m)
       try
           field = getfield(m, name)
           JSON.print(field)
           println()
           json_compat[string(name)] = field
       catch
           println("Skipping $name")
       end
    end
    JSON.json(json_compat)
end

在实际用例中,您可能希望比这个 try-catch 更好地检查可编码性,并且正如已经提到的那样,在生产代码中只转储所有全局变量是不可取的。

这里是REPL中使用的函数

julia> x = 1; y = 2; z = [x,y,[x,y]]; str = "Hello World"; tup = (2,3,(4,5)); dict = Dict([("A", 1), ("B", 2)]);

julia> json_str = globals_to_json(Main);
Skipping Base
Skipping Core
Skipping InteractiveUtils
Skipping Main
{"B":2,"A":1}
{"B":2,"A":1}
Skipping globals_to_json
"Hello World"
[2,3,[4,5]]
1
2
[1,2,[1,2]]

julia> println(json_str)
{"dict":{"B":2,"A":1},"tup":[2,3,[4,5]],"str":"Hello World","x":1,"z":[1,2,[1,2]],"ans":{"B":2,"A":1},"y":2}