以编程方式/动态导入Julia中的模块

时间:2014-12-29 21:33:06

标签: julia

我想知道是否有办法以编程方式或动态地将一组模块导入Julia?例如,如果我有一个符合启动时存在的某些命名约定的文件列表,我可以使用以下内容获取:

module_files = filter(r"^mod[0-9][0-9].jl$", readdir())

可能会返回文件列表["mod00.jl", "mod02.jl", "mod05.jl"],有没有办法导入这些文件中的每个模块。这相当于:

import mod00
import mod02
import mod05
如果我在编写代码时知道这些模块可用,那么在代码中

。或者也许还有其他一些方法可以做得更好。任何建议都会非常感激。

更新

我试图通过宏来做到这一点,但没有运气。例如:

macro import_mod(modn)
    quote
        import $modn
    end
end

function test_mimport()
    module_files = filter(r"^mod[0-9][0-9].jl$", readdir())
    println(module_files)
    for modname in factor_files
        modn = modname[1:end-3]
        println(modn)
        @import_mod modn
    end
end

当我运行时,我得到ERROR: syntax: invalid "import" statement。我尝试了各种逃避策略,但都失败了。

3 个答案:

答案 0 :(得分:7)

注意:请参阅用户1712368(Jameson Nash,Julia dev)的回答,此discussion位于 julia-users 邮件列表中朱莉娅manual的这篇文章,了解为什么正确答案。

这是多重导入表达式的样子,使用Julia版本0.3.4:

julia> parse("import Foo, Bar")
:($(Expr(:toplevel, :($(Expr(:import, :Foo))), :($(Expr(:import, :Bar))))))

julia> dump(ans)
Expr 
  head: Symbol toplevel
  args: Array(Any,(2,))
    1: Expr 
      head: Symbol import
      args: Array(Any,(1,))
        1: Symbol Foo
      typ: Any
    2: Expr 
      head: Symbol import
      args: Array(Any,(1,))
        1: Symbol Bar
      typ: Any
  typ: Any

这是一个以编程方式执行此操作的宏,它需要一个modules参数,该参数可以是:call:vcat ExprSymbol,必须评估为Vector{Symbol}

julia> macro dynamic_import(modules)
           (modules = eval(modules))::Vector{Symbol}
           ex = Expr(:toplevel)
           for m in modules
               push!(ex.args, Expr(:import, m))
           end
           return ex
       end

你也可以概括这一行:

module_files = filter(r"^mod[0-9][0-9].jl$", readdir())

通过将其抽象为一个函数,该函数将RegexString目录路径作为参数并返回Vector{Symbol}

julia> function needed_modules(rx::Regex, dir::String=".")
           module_files = filter(rx, readdir(dir))
           module_syms = map(m -> symbol(split(m, '.')[1]), module_files)
       end
needed_modules (generic function with 2 methods)

所以你可以这样使用它:

julia> @dynamic_import [:Mod01, :Mod02]    # :vcat expression

julia> rx = r"^Mod[0-9][0-9].jl$";

julia> @dynamic_import needed_modules(rx)    # :call expression

julia> modules = needed_modules(rx)
2-element Array{Symbol,1}:
 :Mod01
 :Mod02

julia> @dynamic_import modules    # Symbol

<击> 最后,您可以将其全部包装到module中,以便您可以使用using DynamicImport

注意:目前我尝试从模块运行相同的示例时得到此内容:

julia> using DynamicImport

julia> @dynamic_import [:mod01, :mod02]

julia> rx = r"^mod[0-9][0-9].jl$";

julia> @dynamic_import needed_modules(rx)
ERROR: rx not defined

julia> modules = needed_modules(rx)
2-element Array{Symbol,1}:
 :mod01
 :mod02

julia> @dynamic_import modules
ERROR: modules not defined

但它工作正常如果我在REPL中定义对象,我想这是一个涉及卫生的问题,这是我没有经验的事情,所以我会在julia-users邮件中询问列表。

答案 1 :(得分:3)

import X的功能版本为require("X"),因此您应该可以:

function test_mimport()
    module_files = filter(r"^mod[0-9][0-9].jl$", readdir())
    println(module_files)
    for modname in factor_files
        modn = modname[1:end-3]
        println(modn)
        require(modn)
    end
end

然后,假设每个模块都定义了一个相同名称的模块,您可以将它们收集到一个数组中:

modules = Module[]
...
if isdefined(Main, symbol(modn))
    push!(modules, getfield(Main, symbol(modn))
else
    warn("importing $modn did not defined a module")
end
...
return modules

答案 2 :(得分:0)

我对此解决方案并不感到兴奋,但它似乎有效。基本上我动态创建一个包含导入语句的临时文件然后我include它。所以:

function test_mimport()
    module_files = filter(r"^mod[0-9][0-9].jl$", readdir())
    path, f = mktemp()
    for modname in module_files
        modn = splitext(modname)[1]
        write(f, "import $modn\n")
    end

    close(f)
    include(path)
    rm(path)

end

我很想知道是否有一个更惯用的策略,因为我是朱莉娅的新手,只是通过它的能力填补。

修改

由于Julia还提供include_string方法,因此设置临时文件的策略可能不必要。

在Julia用户列表中,@ Isaiah suggests使用eval(Expr(:import, symbol(modn)))