Как импортировать пользовательский модуль в Юлию
У меня есть модуль, который я написал здесь:
# Hello.jl
module Hello
function foo
return 1
end
end
а также
# Main.jl
using Hello
foo()
Когда я бегу Main
модуль:
$ julia ./Main.jl
Я получаю эту ошибку:
ERROR: LoadError: ArgumentError: Hello not found in path
in require at ./loading.jl:249
in include at ./boot.jl:261
in include_from_node1 at ./loading.jl:320
in process_options at ./client.jl:280
in _start at ./client.jl:378
while loading /Main.jl, in expression starting on line 1
6 ответов
После выпуска Julia v0.7 и v1.0 появился новый ответ на этот вопрос, который несколько отличается. Я просто должен был сделать это, поэтому я решил опубликовать свои результаты здесь.
Как уже объяснялось в других решениях, необходимо включить соответствующий скрипт, который определяет модуль. Однако, поскольку пользовательский модуль не является пакетом, его нельзя загрузить как пакет с тем же using
или же import
команды, которые можно было бы сделать в более старых версиях Julia.
Таким образом, сценарий Main.jl будет написан с относительным импортом:
include("./Hello.jl")
using .Hello
foo()
Я нашел это объясненным просто в комментарии дискурса Стефана Карпински по подобному вопросу. Как он описывает, ситуация также может стать более сложной при работе с подмодулями. Раздел документации по путям к модулям также является хорошим справочным материалом.
Хотя ответ 张实唯 является наиболее удобным, вы не должны использовать include
вне РЕЛ. Если вы пишете программный файл, попробуйте добавить соответствующий каталог в LOAD_PATH. Реми очень хорошо объясняет, как это сделать, но стоит также объяснить, почему вы должны это делать в первую очередь. (Дополнительно из документов: push!(LOAD_PATH, "/Path/To/My/Module/")
но обратите внимание, ваш модуль и ваш файл должны иметь одинаковое имя)
Проблема в том, что все, что вы include
будет определен именно там, где вы звоните include
даже если это также определено в другом месте. Поскольку целью модулей является повторное использование, вы, вероятно, в конечном итоге будете использовать MyModule
в более чем одном файле. Если вы позвоните include
в каждом файле каждый из них будет иметь свое собственное определение MyModule, и даже если они идентичны, это будут разные определения. Это означает, что любые данные, определенные в MyModule
(например, типы данных) не будет таким же.
Чтобы понять, почему это огромная проблема, рассмотрим три файла:
types.jl
module TypeModule
struct A end
export A
end
a_function.jl
include("types.jl")
module AFunctionModule
using TypeModule
function takes_a(a::A)
println("Took A!")
end
export takes_a
end
function_caller.jl
include("a_function.jl")
include("types.jl")
using TypeModule, AFunctionModule
my_a = A()
takes_a(my_a)
Если вы бежите julia function_caller.jl
ты получишь MethodError: no method matching takes_a(::TypeModule.A)
, Это потому что тип A
используется в function_caller.jl отличается от того, который используется в a_function.jl. В этом простом случае вы можете "исправить" проблему, изменив порядок включений в function_caller.jl (или просто удалив include("types.jl")
полностью из function_caller.jl! Это не хорошо!). Но что, если вам нужен другой файл b_function.jl, который также использует тип, определенный в TypeModule
? Тебе придется сделать что-то очень хакерское. Или вы можете просто изменить ваш LOAD_PATH, чтобы модуль определялся только один раз.
РЕДАКТИРОВАТЬ в ответ на xji: чтобы распространять модуль, вы должны использовать Pkg
( документы). Я понял предпосылку этого вопроса как персональный модуль.
Кстати, если вам действительно не нравится идея изменения вашего пути загрузки (даже если он находится только в пределах одного скрипта...), вы можете использовать символическую ссылку вашего модуля в каталог пакета (например, ~/.julia/v0.6/MyModule/MyModule.jl
) а потом Pkg.add(MyModule)
а затем импортировать как обычно. Я считаю, что это немного больше проблем.
Там уже было несколько коротких ответов, но я хотел бы дать более полный ответ, если это возможно.
Когда ты бежишь using MyModule
Юлия ищет его только в списке каталогов, известных как ваш LOAD_PATH
, Если вы печатаете LOAD_PATH
в Julia REPL вы получите что-то вроде следующего:
2-element Array{ByteString,1}:
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/local/share/julia/site/v0.4"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/share/julia/site/v0.4"
Это каталоги, которые Юлия будет искать модули для включения при вводе using Hello
, В приведенном вами примере, так как Hello
не было в вашем LOAD_PATH
Юля не смогла его найти.
Если вы хотите включить локальный модуль, вы можете указать его местоположение относительно вашего текущего рабочего каталога.
julia> include("./src/Hello.jl")
Как только файл был включен, вы можете запустить using Hello
как обычно, чтобы получить все то же поведение. Для одного сценария, это, вероятно, лучшее решение. Однако, если вы обнаружите, что регулярно include()
определенный набор каталогов, вы можете постоянно добавлять их в свой LOAD_PATH
,
Добавление каталогов вLOAD_PATH
Добавление каталогов вручную в ваш LOAD_PATH
может быть больно, если вы хотите регулярно использовать определенные модули, которые хранятся за пределами Julia LOAD_PATH
, В этом случае вы можете добавить дополнительные каталоги в LOAD_PATH
переменная окружения. Джулия будет автоматически искать в этих каталогах всякий раз, когда вы выдаете import
или же using
команда.
Один из способов сделать это - добавить следующее в ваш .basrc
, .profile
, .zshrc
,
export JULIA_LOAD_PATH="/path/to/module/storage/folder"
Это добавит этот каталог к стандартным каталогам, которые Юлия будет искать. Если вы тогда бежите
julia> LOAD_PATH
Должно вернуться
3-element Array{ByteString,1}:
"/path/to/module/storage/folder"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/local/share/julia/site/v0.4"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/share/julia/site/v0.4"
Теперь вы можете свободно бегать using Hello
и Юлия автоматически найдет модуль (если он хранится под ним) /path/to/module/storage/folder
,
Для получения дополнительной информации, посмотрите на эту страницу из Julia Docs.
Я имею Julia Version 1.4.2 (2020-05-23)
. Только этоusing .Hello
работал у меня. Однако перед этим мне пришлось скомпилировать модуль Hello.using .Hello
. Это имеет смысл как для определенных, так и для используемых сценариевHello
находится в том же файле.
Вместо этого мы можем определить Hello
в одном файле и использовать его в другом файле с include("./Hello.jl");using .Hello
Если вы явно не загрузите файл (include("./Hello.jl")
) Юлия ищет файлы модулей в каталогах, определенных в переменной LOAD_PATH.
Смотрите эту страницу.
Если вы хотите получить доступ к функции foo при импорте модуля с помощью "using", вам нужно добавить "export foo" в заголовок модуля.