在 Julia 中使用 eval 和符号为数组赋值

assign values to arrays with eval and symbols in Julia

我有一个有 3 个键的字典,每个键都有任意二维数组。我想将这些值(二维数组)中的每一个分配给新创建的数组。所以我写了这个:

levels = (:easy, :medium, :hard)
easy = []; medium = []; hard = [];
curriculum = Dict((k=>rand(3,3) for k in levels)...); # dictionary with 3 keys - each key is a symbol
for level in levels
    eval(level) = curriculum[level]
end

执行过程中没有问题,但之后检查easy、medium、hard数组时,里面没有矩阵。

这样做的正确方法是什么? B.R.

(已编辑)

据我了解,在循环迭代期间,eval(level) 的行为类似于本地绑定。因此,在迭代结束时它不会记住任何东西。但为什么?以及如何再次转换为全局?

编辑 Ismael 在已接受的答案和评论中指出了更好的方法。即:

global level = level is not necessary, see my answer, the issue is that if you want to interpolate a symbol into an expression as a symbol instead of as an identifier, then you need to wrap the symbol into another quote expression.


警告:这是(几乎可以肯定)不是开始完成您想做的任何事情的最佳方式。 julia 中的元编程非常强大和有用,但你应该很少需要使用 eval。您可以阅读更多相关信息 here。如果你问另一个关于你最终目标细节的问题,你可能会得到更好的答案:)

尽管如此:

如果您想以这种方式进行赋值,则必须创建一个表达式 Expr,将矩阵对象赋值给具有所需名称的变量。但是因为 eval 总是在全局范围内执行语句 你需要让你想要使用的变量在全局范围内可用。

 for level in levels
     global level = level
     eval(:($level = curriculum[level]))
 end

或使用@eval 宏:

for level in levels
     global level = level
     @eval $level = curriculum[level]
 end

There is no problem during execution but when I check the easy, medium or hard arrays after, there are no matrices inside.

What I understand is that during the loop iteration eval(level) behaves like local binding. Thus, at the end of the iteration it does not remember anything. But why? And how to convert to global again ?

问题是您在 for 循环内的每次迭代中定义然后重新定义 eval 函数,而不是像您相信的那样进行赋值。


easy = []; medium = []; hard = []

1.- 无需预定义此变量。


eval(level) = curriculum[level]

2.- 警告:这被解释为短样式函数定义!

julia> eval(level) = curriculum[level]
eval (generic function with 1 method)

julia> levels = :easy, :medium, :hard
(:easy, :medium, :hard)

julia> curriculum = Dict((k => rand(3, 3) for k in levels)...)
Dict{Symbol,Array{Float64,2}} with 3 entries:
  :medium => [0.230877 0.244128 0.205712; 0.649405 0.887568 0.957849; 0.245076 0.476088 0.160561]
  :hard   => [0.0424943 0.157261 0.798607; 0.590535 0.78125 0.704322; 0.555827 0.675355 0.74026]
  :easy   => [0.715595 0.914093 0.517973; 0.750787 0.489784 0.491666; 0.1966 0.133281 0.249144]

julia> for level in levels
           @eval $level = curriculum[$(Meta.quot(level))]
       end

julia> easy
3×3 Array{Float64,2}:
 0.715595  0.914093  0.517973
 0.750787  0.489784  0.491666
 0.1966    0.133281  0.249144

3.- 在for循环中,在第一次迭代中,$level被解释为easy变量标识符,而$(Meta.quot(level))被解释为符号:easy,为此需要额外级别的 quoting

julia> Meta.quot(:foo)   
:(:foo)                  
                     
julia> Expr(:quote, :foo)
:(:foo)