【问题标题】:How to save all global variables from a Julia code into a file?如何将 Julia 代码中的所有全局变量保存到文件中?
【发布时间】:2021-02-25 04:41:39
【问题描述】:

我正在尝试将 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")

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

【问题讨论】:

  • 你为什么要做这样的事情?
  • 我想执行一个需要很长时间才能运行的模拟代码,所以我决定将数据保存到一个 json 文件中。为了在另一个文件中再次处理数据,我需要用于执行模拟的参数,因为我编写的许多用于分析数据的函数调用代码中的全局变量。因此,如果不导入使用相同名称的变量,所有这些函数都会失败,因此为了分离代码的“模拟”和“分析”部分,我需要保存全局变量以在另一个文件中读取它。希望你明白我的意思。
  • 由于我经常更改参数,因此我想将它们视为我的数据的一部分 - 包括变量名称及其值,以便我可以随时在单独的文件中读取它们。
  • 我已经猜到了,但想确定:D 正确的解决方案是不要以这种方式编写依赖于全局变量的函数(作为“输入参数”)。
  • 一个更优雅的解决方案可能是,例如,编写一个带有序列化/反序列化函数的“模拟对象”类型,或者只是一个字典,然后使用结构解包(Parameters.jl 或类似的东西) .

标签: json variables save julia metaprogramming


【解决方案1】:

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

对于交互式使用,您可以使用@save filename 将所有变量保存在当前模块的全局范围内。更永久的代码应该更喜欢显式形式以避免保存不需要的变量。

使用 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 找到实现此功能的代码。它通过在当前模块上调用names(docs) 函数然后过滤结果以查找可以/应该保存的变量来工作。启动 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}

【讨论】:

    猜你喜欢
    • 2019-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-30
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    相关资源
    最近更新 更多