Подтвердить что ты не робот

Как перезагрузить модуль в активной сессии 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.

4b9b3361

Ответ 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.