web-dev-qa-db-ja.com

編集後にアクティブなジュリアセッションでモジュールをリロードするにはどうすればよいですか?

2018 Update:この質問に対する答えは長年にわたって複数回変更されているため、必ずすべての回答を確認してください。この更新の時点で、おそらく_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
_

現在、アクティブなジュリアセッションでモジュールをリロードしようとしています。やってみる

_using ctbTestModule
_

しかし、f1(1)はまだ_2_を返します。次に試す

_reload("ctbTestModule")
_

here が提案されているように、f1(1)はまだ_2_を返します。最後に、私は試します:

_include("/SomeAbsolutePath/ctbTestModule.jl")
_

こちら 、これはnot理想的です。現在のディレクトリが「/ SomeAbsolutePath」ではない可能性があるため、絶対パスを完全に入力する必要があるためです。警告メッセージ_Warning: replacing module ctbTestModule_が表示されますが、これは有望に聞こえますが、f1(1)はまだ_2_を返します。

現在のジュリアセッションを閉じ、新しいセッションを開始し、_using ctbTestModule_と入力すると、目的の動作が得られます。つまり、f1(1)は_3_を返します。しかし、明らかに、Juliaを再起動せずにこれをやりたいです。

だから、私は何を間違っていますか?

その他の詳細:Ubuntu 14.04上のJulia v0.2。

55
Colin T Bowers

この問題の基礎は、モジュールのリロードの合流ですが、モジュール内の事柄を再定義できないことですMainこちらのドキュメントを参照 )-つまり 少なくとも新しい関数workspace()が利用可能になるまで 2014年7月13日。 0.3プレリリースにはそれが必要です。

Workspace()の前

次の単純なモジュールを検討してください

module TstMod
export f

function f()
   return 1
end

end

次にそれを使用します。

Julia> using TstMod

Julia> f()
1

関数f()がreturn 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

Workspace()を使用する

ただし、新しい関数workspace()はMainリロードの準備TstMod

Julia> workspace()

Julia> reload("TstMod")

Julia> using TstMod

Julia> f()
2

また、前のMainLastMain

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

Julia> LastMain.f()
1
55
waTeim

パッケージReviseを使用します。

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

include("src/my_module.jl")
using Revise
import my_module

新しいREPLセッションでこれを開始する必要がある場合があります。 importの代わりにusingを使用していることに注意してください。これは、usingMainモジュールの関数を再定義しないためです(@Maciek Leksと@waTeimで説明)。

他の解決策workspace()と比較したRevise.jlの2つの利点は、(1)はるかに高速であり、(2 ) このGitHubの問題 で説明されているように、workspace()は0.7で非推奨になったため、将来も保証されます。

Julia> VERSION
v"0.7.0-DEV.3089"

Julia> workspace()
ERROR: UndefVarError: workspace not defined

そして、GitHubの貢献者が推奨するRevise.jl

「ワークスペースは非推奨です。代わりにRevise.jlをチェックしてください」などのメッセージを追加する必要がありますか?

Julia 0.6.3でも、モジュールがimportなどの他のモジュールを呼び出すと、workspace()reload、およびDataFramesの3つの以前のソリューションは失敗します。 3つの方法すべてで、同じREPLでそのモジュールを2回呼び出したときに同じエラーが発生しました。

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.

Juliaセッションの再起動は機能しましたが、面倒でした。 再エクスポートパッケージのこの問題 を見つけましたが、同様のエラーメッセージが表示されます。

MethodError: all(::Reexport.##2#6, ::Array{Any,1}) is ambiguous.

そして、1人の貢献者の提案に従いました:

これは、workspace()を使用せずに発生しますか?この関数は、パッケージとの相互作用が不十分なことで有名です。これが、0.7で非推奨になった理由の1つです。

13
mmorin

私の謙虚な意見では、より良い方法は、報告された問題に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を使用する場合の欠点:

  • すべてのエクスポートされた名前のすべての呼び出しで完全修飾名が必要です

編集済み:以下の会話に従って、「短所...」から「エクスポートされていない名前にさえも、モジュールへのフルアクセス」を破棄しました。

10
Maciek Leks

ジュリアではv0.6.を使用しているようですworkspace()no必要です:単純にreload(MyModule)アクティブなREPLセッションで、期待どおりに動作します(MyModuleを含むソースファイルに加えられた変更は、アクティブなREPLセッション)に反映されます。

これは、importまたはsingのいずれかによってスコープに取り込まれたモジュールに適用されます

8
pragMATHiC

新しいモジュールをゼロから作成したかったため、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をリロードせずにすべてを更新できます。

1
Carl Morris