Программно / динамически импортировать модули в 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 ответов
версия функция 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
Примечание: пожалуйста, обратитесь к user1712368 (Джеймсон Нэш, Джулия Дев) ответ, это обсуждение на Юля-пользователи список рассылки и эта запись Julia руководство, чтобы узнать, почему это не правильный ответ.
вот как выглядит выражение множественного импорта, используя 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
Expr
или Symbol
, который оценивает в 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())
абстрагируя его в функцию, которая принимает Regex
и a String
путь к каталогу в качестве аргументов и возвращает 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
Наконец, вы можете обернуть все это в модуль таким образом, вы можете использовать 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.
Я не в восторге от этого решения, но это, кажется, работает. В основном я динамически создаю временный файл, содержащий инструкции импорта, которые я тогда 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
метод.
в списке Юлия-пользователь, @Isaiah также предполагает используя eval(Expr(:import, symbol(modn)))