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

Col*_*ers 56 module julia

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

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

module ctbTestModule
export f1
f1(x) = x + 1
end
Run Code Online (Sandbox Code Playgroud)

我在一个运行"〜/ .juliarc.jl"的终端中点燃Julia.启动代码包括以下行:

push!(LOAD_PATH, "/SomeAbsolutePath/")
Run Code Online (Sandbox Code Playgroud)

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

using ctbTestModule
Run Code Online (Sandbox Code Playgroud)

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

module ctbTestModule
export f1
f1(x) = x + 2
end
Run Code Online (Sandbox Code Playgroud)

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

using ctbTestModule
Run Code Online (Sandbox Code Playgroud)

f1(1)仍然返回2.接下来我尝试:

reload("ctbTestModule")
Run Code Online (Sandbox Code Playgroud)

正如这里所建议的,但f1(1)仍然会回归2.最后,我尝试:

include("/SomeAbsolutePath/ctbTestModule.jl")
Run Code Online (Sandbox Code Playgroud)

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

如果我关闭当前的Julia会话,启动一个新会话并输入using ctbTestModule,我现在得到所需的行为,即f1(1)返回3.但显然我想在重新启动朱莉娅的情况下这样做.

那么,我做错了什么?

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

waT*_*eim 55

这个问题的基础是重新加载模块的汇合,但是无法重新定义模块Main中的东西(参见此处的文档) - 至少在7月13 日新功能工作空间()可用之前 2014年.预发布0.3的最新版本应该有它.

工作空间之前()

考虑以下简单模块

module TstMod
export f

function f()
   return 1
end

end
Run Code Online (Sandbox Code Playgroud)

然后用它....

julia> using TstMod

julia> f()
1
Run Code Online (Sandbox Code Playgroud)

如果函数f()被更改为返回2并且模块被重新加载,则f实际上已更新.但未在模块Main中重新定义.

julia> reload("TstMod")
Warning: replacing module TstMod

julia> TstMod.f()
2

julia> f()
1
Run Code Online (Sandbox Code Playgroud)

以下警告使问题清楚

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
Run Code Online (Sandbox Code Playgroud)

使用工作区()

但是,新函数workspace()清除Main准备重新加载TstMod

julia> workspace()

julia> reload("TstMod")

julia> using TstMod

julia> f()
2
Run Code Online (Sandbox Code Playgroud)

此外,前一个Main存储为LastMain

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

julia> LastMain.f()
1
Run Code Online (Sandbox Code Playgroud)

  • 2020年这个问题的解决方案是什么?发布的答案似乎都不起作用(未定义重新加载功能,1.5.3 中的工作空间也未定义)。清除环境或重新加载特定模块似乎是 IDE 的一个基本且重要的功能。 (6认同)
  • +1 +勾选非常感谢。一旦StackOverflow让我回来就奖励赏金:-) (2认同)

mig*_*rin 16

使用包Revise,例如

Pkg.add("Revise") # do this only once

include("src/my_module.jl")
using Revise
import my_module
Run Code Online (Sandbox Code Playgroud)

您可能需要在新的REPL会话中启动它.注意使用import而不是using,因为using没有重新定义Main模块中的函数(如@Maciek Leks和@waTeim所解释的).

其他解决方案:与之Revise.jl相比的两个优点workspace()是:(1)它更快,(2)它是面向未来的workspace(),正如在这个GitHub问题中所讨论的那样在0.7中被弃用了:

julia> VERSION
v"0.7.0-DEV.3089"

julia> workspace()
ERROR: UndefVarError: workspace not defined
Run Code Online (Sandbox Code Playgroud)

和GitHub的贡献者建议Revise.jl:

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

即使在朱莉娅0.6.3,三个以前的解决方案workspace(),import以及reload失败当模块调用其他模块,如DataFrames.使用这三种方法,当我在同一个REPL中第二次调用该模块时,我得到了同样的错误:

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

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

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.
Run Code Online (Sandbox Code Playgroud)

重启Julia会话很有效,但很麻烦.我在Reexport包中发现了这个问题,并出现了类似的错误消息:

MethodError: all(::Reexport.##2#6, ::Array{Any,1}) is ambiguous.
Run Code Online (Sandbox Code Playgroud)

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

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

  • 谢谢你.我在问题的顶部添加了一个横幅,表明读者会查看所有答案(特别是这一个),因为最佳解决方案在过去几年中已经多次改变. (3认同)

Mac*_*eks 10

在我看来,更好的方法是import从一开始就使用而不是using报告的问题.

考虑一下模块:

module ModuleX1
  export produce_text
  produce_text() = begin
    println("v1.0") 
  end
  println("v1.0 loaded")
end
Run Code Online (Sandbox Code Playgroud)

然后在REPL中:

julia> import ModuleX1
v1.0 loaded

julia> ModuleX1.produce_text()
v1.0
Run Code Online (Sandbox Code Playgroud)

更新模块的代码并保存:

module ModuleX1
  export produce_text
  produce_text() = begin
    println("v2.0")  
  end
  println("v2.0 loaded")
end
Run Code Online (Sandbox Code Playgroud)

接下来,在REPL中:

julia> reload("ModuleX1")
Warning: replacing module ModuleX1
v2.0 loaded

julia> ModuleX1.produce_text()
v2.0
Run Code Online (Sandbox Code Playgroud)

使用的优点importusing:

  • 避免函数调用中的歧义(重新加载后调用什么:ModuleX1.produce_text()或produce_text()?)
  • 不必workspace()为了摆脱歧义而打电话

使用import过的缺点using:

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

编辑:根据下面的对话,放弃了"缺点..."中的"完全访问模块,甚至是未导出的名称".

  • 这是有趣的.一个简单的问题:我认为只要我完全限定了呼叫,我就可以通过`using'完全访问模块中的非导出名称.这不正确吗? (2认同)

pra*_*HiC 8

在朱莉娅v0.6.0好像使用工作区()没有存在的必要:我可以简单地重新加载(MyModule中)在活动REPL会话,它可以作为到包含MyModule的反映在活跃的源文件的预期(chages REPL会议).

这适用于通过导入使用进入范围的模块