从Julia中的字典以编程方式创建局部变量

时间:2016-01-28 02:22:09

标签: julia julia-jump

考虑以下功能:

function func(vars::Dict{Symbol, Any})

end

我想在func的范围内创建局部变量, 哪里: 变量名都是varsvars的关键 变量值是与给定键对应的eval()中的值。

我知道我可以使用for (k, v) in vars eval(:($k = $v)) end 之类的内容:

JuMP

但是,这将定义全局范围内的变量,这会产生性能影响并可能覆盖现有的全局变量。

P.S。如果您的建议与我要采用的方法截然不同,我会添加一个上下文。我正在围绕JuMP实现一个包装器,允许用户使用任意约束表达式动态创建优化模型。由于约束表达式是使用符号定义的,并且import pandas as pd data = pd.read_csv(filename) data2 = df[['A','B','C']] #put 'A' 'B' 'C' in the desired order data2.to_csv(filename) 要求在当前作用域中定义这些符号,因此我希望用户将这些符号及其值在字典中提供给函数。全局定义符号将是麻烦的,因为用户理想情况下应能够使用相同的约束表达式(即相同的符号)但不同的值多次运行该函数。

1 个答案:

答案 0 :(得分:1)

注意:我不是元编程专家!

认为你可以做这样的事情,不是使用泛型函数,而是使用宏或生成函数。

基于此:

julia> macro bar(dict)
           dump(dict, 10)
       end

julia> @bar Dict(:foo => "foo", :bar => "bar", :baz => "baz");
Expr 
  head: Symbol call
  args: Array(Any,(4,))
    1: Symbol Dict
    2: Expr 
      head: Symbol =>
      args: Array(Any,(2,))
        1: Expr 
          head: Symbol quote
          args: Array(Any,(1,))
            1: Symbol foo
          typ: Any
        2: ASCIIString "foo"
      typ: Any
    3: Expr 
      head: Symbol =>
      args: Array(Any,(2,))
        1: Expr 
          head: Symbol quote
          args: Array(Any,(1,))
            1: Symbol bar
          typ: Any
        2: ASCIIString "bar"
      typ: Any
    4: Expr
      head: Symbol =>
      args: Array(Any,(2,))
        1: Expr
          head: Symbol quote
          args: Array(Any,(1,))
            1: Symbol baz
          typ: Any
        2: ASCIIString "baz"
      typ: Any
  typ: Any

我能够做这样的事情,它可以做更多的错误检查,并且通用宏会使开发分支中的这更容易(至少用于错误检查):

julia> macro foo(dict)
           blk = Expr(:block)
           if dict.head == :call && dict.args[1] == :Dict
               for arg in dict.args[2:end]
                   sym = arg.args[1].args[1]
                   val = arg.args[2]
                   push!(blk.args, esc(:($sym = $val)))
               end
           else
               error("Need a Dict{Symbol, Any}")
           end
           blk
       end

julia> @foo Dict(:foo => "foo", :bar => "bar", :baz => "baz");

julia> @show foo bar baz;
foo = "foo"
bar = "bar"
baz = "baz"

julia> let    # local scope
           @foo Dict(:foo => "foo", :bar => "bar", :baz => "baz")
           @show foo bar baz
       end;
foo = "foo"
bar = "bar"
baz = "baz"

请注意,您无法创建dict变量,然后将其传递给@foo宏(再次generic macros可以使这更容易,因为Symbol也可以使用方法和派遣错误?):

julia> dict = Dict(:foo => "foo", :bar => "bar", :baz => "baz");

julia> @foo dict
ERROR: type Symbol has no field head

此时的内容如下:

@foo a 1 b 2 c 3

@foo :a=>1 :b=>2 :c=>3

恕我直言会更好。

如果有人解释我为什么这不是最佳的,我会非常感激!这个答案应该是一个评论,但它是很多代码。

我将尝试使用通用宏和生成的函数实现类似的功能并更新帖子。