Как перезагрузить модуль в активной сессии Julia после редактирования?
Обновление 2018 года: обязательно проверьте все ответы, так как ответ на этот вопрос несколько раз менялся с годами. На момент этого обновления ответ Revise.jl
вероятно, является лучшим решением.
У меня есть файл "/SomeAbsolutePath/ctbTestModule.jl", содержимое которого:
module ctbTestModule
export f1
f1(x) = x + 1
end
Я запускаю Джулию в терминале, который запускает "~/.juliarc.jl". Код запуска включает в себя строку:
push!(LOAD_PATH, "/SomeAbsolutePath/")
Следовательно, я могу сразу набрать в консоли Юлия:
using ctbTestModule
загрузить мой модуль. Как и ожидалось, f1(1)
возвращает 2
. Теперь я вдруг решил, что хочу редактировать f1
. Я открываю "/SomeAbsolutePath/ctbTestModule.jl" в редакторе и изменяю содержимое на:
module ctbTestModule
export f1
f1(x) = x + 2
end
Сейчас я пытаюсь перезагрузить модуль в моей активной сессии Джулии. я попробую
using ctbTestModule
но f1(1)
все еще возвращает 2
. Далее я пытаюсь:
reload("ctbTestModule")
как предложено здесь, но f1(1)
все еще возвращает 2
. Наконец, я пытаюсь:
include("/SomeAbsolutePath/ctbTestModule.jl")
как здесь предлагается, что не является идеальным, поскольку мне приходится вводить полный абсолютный путь, поскольку текущим каталогом может быть не "/SomeAbsolutePath". Я получаю предупреждающее сообщение Warning: replacing module ctbTestModule
который звучит многообещающе, но f1(1)
все еще возвращает 2
.
Если я using ctbTestModule
текущий сеанс Julia, начну новый и using ctbTestModule
, я получу желаемое поведение, т.е. f1(1)
вернет 3
. Но, очевидно, я хочу сделать это без перезапуска Джулии.
Итак, что я делаю не так?
Другие детали: Julia v0.2 на Ubuntu 14.04.
Ответы
Ответ 1
Основой этой проблемы является слияние перезагрузки модуля, но не в состоянии переопределить вещь в модуле Главная (см. документацию здесь) - это по крайней мере до тех пор, пока новая рабочая область() не станет доступна 13 июля 2014 года. Последние версии предварительного выпуска 0.3 должны иметь он.
До рабочей области()
Рассмотрим следующий упрощенный модуль
module TstMod
export f
function f()
return 1
end
end
Затем используйте его....
julia> using TstMod
julia> f()
1
Если функция f() изменена для возврата 2, и модуль перезагружен, на самом деле обновляется f. Но не переопределяется в модуле Главная.
julia> reload("TstMod")
Warning: replacing module TstMod
julia> TstMod.f()
2
julia> f()
1
Следующие предупреждения устраняют проблему.
julia> using TstMod
Warning: using TstMod.f in module Main conflicts with an existing identifier.
julia> using TstMod.f
Warning: ignoring conflicting import of TstMod.f into Main
Использование рабочей области()
Однако новая функция рабочая область() очищает Главная, готовя ее к перезагрузке TstMod
julia> workspace()
julia> reload("TstMod")
julia> using TstMod
julia> f()
2
Кроме того, предыдущий Основной хранится как LastMain
julia> whos()
Base Module
Core Module
LastMain Module
Main Module
TstMod Module
ans Nothing
julia> LastMain.f()
1
Ответ 2
По моему скромному мнению, лучше всего использовать import
с самого начала, а не using
для сообщаемой проблемы.
Рассмотрим модуль:
module ModuleX1
export produce_text
produce_text() = begin
println("v1.0")
end
println("v1.0 loaded")
end
Тогда в REPL:
julia> import ModuleX1
v1.0 loaded
julia> ModuleX1.produce_text()
v1.0
Обновите код модуля и сохраните его:
module ModuleX1
export produce_text
produce_text() = begin
println("v2.0")
end
println("v2.0 loaded")
end
Далее в REPL:
julia> reload("ModuleX1")
Warning: replacing module ModuleX1
v2.0 loaded
julia> ModuleX1.produce_text()
v2.0
Преимущества использования import
перед using
:
- Избегать неоднозначности в вызовах функций (что вызывать: ModuleX1.produce_text() или product_text() после перезагрузки?)
- не нужно вызывать
workspace()
, чтобы избавиться от неоднозначности
Недостатки использования import
перед using
:
- необходимо полное имя в каждом вызове для каждого экспортируемого имени
Отредактировано: исключено "полный доступ к модулю, даже к неэкспортированным именам" из "Недостатки..." согласно беседе ниже.
Ответ 3
Используйте пакет Revise
, например,
Pkg.add("Revise") # do this only once
include("src/my_module.jl")
using Revise
import my_module
Возможно, вам придется начать это в новом сеансе REPL. Обратите внимание на использование import
вместо using
, потому что using
не переопределяет функцию в Main
модуле (как объяснено @Maciek Leks и @waTeim).
Другие решения: Два преимущества Revise.jl
по сравнению с workspace()
заключаются в том, что (1) он намного быстрее и (2) он Revise.jl
на будущее, поскольку workspace()
устарел в версии 0.7, как обсуждалось в этом выпуске GitHub:
julia> VERSION
v"0.7.0-DEV.3089"
julia> workspace()
ERROR: UndefVarError: workspace not defined
и участник GitHub рекомендовал Revise.jl
:
Должны ли мы добавить сообщение типа "рабочее пространство устарело, вместо этого проверьте Revise.jl"?
Даже в Julia 0.6.3 три предыдущих решения workspace()
, import
и reload
терпят неудачу, когда модуль DataFrames
другие модули, такие как DataFrames
. Со всеми тремя методами я получил ту же ошибку, когда я вызвал этот модуль во второй раз в том же REPL:
ERROR: LoadError: MethodError: all(::DataFrames.##58#59, ::Array{Any,1}) is ambiguous. Candidates: ...
Я также получил много предупреждающих сообщений, таких как:
WARNING: Method definition macroexpand(Module, ANY) in module Compat at /Users/mmorin/.julia/v0.6/Compat/src/Compat.jl:87 overwritten in module Compat at /Users/mmorin/.julia/v0.6/Compat/src/Compat.jl:87.
Перезапуск сеанса Джулии работал, но это было громоздко. Я нашел эту проблему в пакете Reexport, с похожим сообщением об ошибке:
MethodError: all(::Reexport.##2#6, ::Array{Any,1}) is ambiguous.
и последовал предложению одного участника:
Это происходит без использования workspace()? Эта функция печально известна тем, что плохо взаимодействует с пакетами, поэтому отчасти она устарела в версии 0.7.
Ответ 4
В julia v0.6.0 кажется, что использование workspace() больше нет: я могу просто перезагрузить (MyModule ) в активном сеансе REPL, и он работает как ожидалось (chages, сделанные в исходный файл, содержащий MyModule, отражаются в активном сеансе REPL).
Это относится к модулям, которые были добавлены в область видимости с помощью import или , используя
Ответ 5
Я хотел создать новый модуль с нуля, и попробовал разные ответы с 1.0 и не получил удовлетворительного результата, но я обнаружил, что следующее работает для меня:
От Julia REPL в каталоге, который я хочу использовать для моего проекта, я запускаю
pkg> generate MyModule
Это создает подкаталог, подобный следующей структуре:
MyModule
├── Project.toml
└── src
└── MyModule.jl
Я поместил свой код модуля в MyModule.jl
. Я MyModule
в каталог MyModule
(или открываю его в моей IDE) и добавляю файл Scratch.jl
со следующим кодом:
Pkg.activate(".")
using Revise
import MyModule
Затем я могу добавить свой код для проверки ниже, и все обновляется без перезагрузки REPL.