在给定范围/上下文中以eict形式进行评估的最佳方法是什么?

时间:2017-01-13 16:29:36

标签: julia

我有一个字符串,例如z[2]我想在上下文中eval,例如Dict(:z => 1:10)

最好的方法是什么?

我可以做一些工作,但速度很慢。

function replace_expr(expr, d::Dict)
    return expr
end

function replace_expr(s::Symbol, d::Dict)
    get(d, s, s)
end

function replace_expr(expr::Expr, d::Dict)
    return Expr(replace_expr(expr.head, d),
                [replace_expr(e, d) for e in expr.args]...)
end


function eval_with(context::Dict{Symbol, Any}, expr_string::AbstractString)
    # E.g. :abc => :(s[:abc])
    d = Dict(k => :(s[$(Meta.quot(k))]) for k in keys(context))
    ex = parse("s -> $expr_string")
    ex = replace_expr(ex, d)
    return eval(ex)(context)
end

以下是测试

function make_context()
    x = 1
    y = "foo"
    z = 2:5

    Dict(
        :x => x,
        :y => y,
        :z => z
    )
end

const context = make_context()

@test eval_with(context, "x + 3") == 4
@test eval_with(context, "string(1, y, 1)") == "1foo1"
@test eval_with(context, "z[2]") == 3

@time eval_with(context, "z[2]")
# 0.004739 seconds (767 allocations: 40.728 KB)

2 个答案:

答案 0 :(得分:2)

这似乎是一个可以依靠朱莉娅的内置表达评估机制的地方。 -采用可选参数:要进行评估的模块。

您可以通过编程方式创建新模块:

eval

您可以使用julia> M = Module() anonymous

将字典中的值分配到该模块中
eval

现在,当然,您可以在模块的上下文中评估自定义字符串。

julia> context = Dict(
               :x => 1,
               :y => "foo",
               :z => 2:5
           );

julia> for (k,v) in context
           eval(M, :($k = $v))
       end

julia> M.x
1

julia> M.y
"foo"

像这样的动态评估不会成为朱莉娅闪耀的地方。我认为这将是最好的:

julia> eval(M, parse("x+3"))
4

julia> eval(M, parse("string(1, y, 1)"))
"1foo1"

请注意,这与您上面编写的代码略有不同;您的上下文中的变量仅在开头填充...并且可能会被新的评估更改。

关于使用julia> @time eval(M, parse("z[2]")) 0.000284 seconds (13 allocations: 672 bytes) 3 的{​​{3}} usual适用。通常还有其他更好的方法来构建您的程序,这些方法将更高效,更易理解,更易于维护。

答案 1 :(得分:2)

如果您事先知道这些值,则可以通过元编程来使用eval。这个的宏由Parameters.jl提供:

d = Dict{Symbol,Any}(:a=>5.0,:b=>2,:c=>"Hi!")
@unpack a, c = d
a == 5.0 #true
c == "Hi!" #true