如何在编辑后在活动的Julia会话中重新加载模块?

时间:2014-07-30 04:39:54

标签: module julia

2018更新:请务必检查所有回复,因为多年来此问题的答案已多次更改。在此次更新时,Revise.jl答案可能是最佳解决方案。

我有一个文件“/SomeAbsolutePath/ctbTestModule.jl”,其内容是:

module ctbTestModule
export f1
f1(x) = x + 1
end

我在一个运行“〜/ .juliarc.jl”的终端中启动了Julia。启动代码包括以下行:

push!(LOAD_PATH, "/SomeAbsolutePath/")

因此我可以立即输入Julia控制台:

using ctbTestModule

加载我的模块。按预期f1(1)返回2。现在我突然决定要编辑f1。我在编辑器中打开“/SomeAbsolutePath/ctbTestModule.jl”,并将内容更改为:

module ctbTestModule
export f1
f1(x) = x + 2
end

我现在尝试在我的活跃Julia会话中重新加载模块。我试试

using ctbTestModule

f1(1)仍会返回2。接下来我试试:

reload("ctbTestModule")

按照建议here,但f1(1)仍然返回2。最后,我尝试:

include("/SomeAbsolutePath/ctbTestModule.jl")

建议here理想,因为我必须输入完整的绝对路径,因为当前目录可能不是“/ SomeAbsolutePath”。我收到了警告信息Warning: replacing module ctbTestModule,这听起来很有希望,但f1(1)仍然会返回2

如果我关闭当前的Julia会话,启动一个新会话并输入using ctbTestModule,我现在可以获得所需的行为,即f1(1)返回3。但显然我想这样做没有重新启动Julia。

那么,我做错了什么?

其他细节:Ubuntu 14.04上的Julia v0.2。

5 个答案:

答案 0 :(得分:52)

此问题的基础是重新加载模块的汇合,但无法重新定义模块 Main see the documentation here)中的内容 - - 这是at least until the new function workspace() was made available于2014年7月13日。最新版本的0.3预发布应该有它。

在工作空间()

之前

考虑以下简单模块

module TstMod
export f

function f()
   return 1
end

end

然后使用它....

julia> using TstMod

julia> f()
1

如果功能 f ()更改为返回2 并重新加载模块,则 f 实际上已更新。但未在模块 Main 中重新定义。

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

此外,之前的 Main 存储为 LastMain

julia> whos()
Base                          Module
Core                          Module
LastMain                      Module
Main                          Module
TstMod                        Module
ans                           Nothing

julia> LastMain.f()
1

答案 1 :(得分:10)

我认为,更好的方法是从一开始就使用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()或produce_text()
  • 不必为了摆脱歧义而致电workspace()

使用import而不是using的缺点:

  • 每次调用时都需要每个导出名称的完全限定名称

编辑:放弃&#34;完全访问模块,甚至是未导出的名称&#34;来自&#34;缺点......&#34;根据下面的对话。

答案 2 :(得分:10)

使用包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.jlworkspace()相比的两个优点是(1)它更快,(2)它是面向未来的,因为{ {1}}已弃用,如this GitHub issue中所述:

workspace()

并且GitHub撰稿人建议julia> VERSION v"0.7.0-DEV.3089" julia> workspace() ERROR: UndefVarError: workspace not defined

  

我们是否应该添加一些消息,例如“工作空间已弃用,请查看Revise.jl”?

即使在Julia 0.6.3中,Revise.jlworkspace()import之前的三个解决方案在模块调用其他模块时失败,例如reload。使用这三种方法,当我在同一个REPL中第二次调用该模块时,我得到了同样的错误:

DataFrames

我还收到许多警告信息,例如:

ERROR: LoadError: MethodError: all(::DataFrames.##58#59, ::Array{Any,1}) is ambiguous. Candidates: ...

重新启动Julia会话有效,但很麻烦。我找到了this issue in the Reexport package,其中包含类似的错误消息:

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.

并遵循一位撰稿人的建议:

  

不使用workspace()会发生这种情况吗?该函数因与软件包交互不佳而臭名昭着,这也是它在0.7中被弃用的部分原因。

答案 3 :(得分:7)

在julia v0.6.0 中,似乎使用 workspace()需要更长时间没有:我只需重新加载(MyModule) )在一个活动的REPL会话中,它按预期工作(对包含MyModule的源文件的chages反映在活动的REPL会话中)。

这适用于已通过导入使用

进入范围的模块

答案 4 :(得分:0)

我想从头开始创建一个新模块,并尝试使用1.0的不同答案,但未获得令人满意的结果,但是我发现以下方法对我有用:

在我要用于我的项目的目录中的Julia REPL中

pkg> generate MyModule

这将创建一个类似于以下结构的子目录:

MyModule
├── Project.toml
└── src
    └── MyModule.jl

我将模块代码放入MyModule.jl中。我转到目录MyModule(或在我的IDE中打开它),并使用以下代码添加文件Scratch.jl

Pkg.activate(“.”)
using Revise
import MyModule

然后,我可以在下面添加我的代码进行测试,并且所有内容都会更新,而无需重新加载REPL。