module - pse - ¿Cómo recargo un módulo en una sesión Julia activa después de una edición?
flypass registration (4)
Actualización 2018: asegúrese de verificar todas las respuestas, ya que la respuesta a esta pregunta ha cambiado varias veces a lo largo de los años. En el momento de esta actualización, la respuesta Revise.jl
es probablemente la mejor solución.
Tengo un archivo "/SomeAbsolutePath/ctbTestModule.jl", cuyo contenido es:
module ctbTestModule
export f1
f1(x) = x + 1
end
Arranco a Julia en una terminal, que ejecuta "~ / .juliarc.jl". El código de inicio incluye la línea:
push!(LOAD_PATH, "/SomeAbsolutePath/")
Por lo tanto, puedo escribir inmediatamente en la consola de Julia:
using ctbTestModule
para cargar mi módulo Como se esperaba, f1(1)
devuelve 2
. Ahora, de repente, decido que quiero editar f1
. Abro "/SomeAbsolutePath/ctbTestModule.jl" en un editor, y cambio el contenido a:
module ctbTestModule
export f1
f1(x) = x + 2
end
Ahora trato de volver a cargar el módulo en mi sesión activa de Julia. lo intento
using ctbTestModule
pero f1(1)
todavía devuelve 2
. A continuación, intento:
reload("ctbTestModule")
como se sugiere here , pero f1(1)
aún devuelve 2
. Finalmente, intento:
include("/SomeAbsolutePath/ctbTestModule.jl")
como se sugiere here , que no es ideal ya que tengo que escribir la ruta absoluta completa ya que el directorio actual podría no ser "/ SomeAbsolutePath". Warning: replacing module ctbTestModule
el mensaje de advertencia Warning: replacing module ctbTestModule
que suena prometedor, pero f1(1)
aún devuelve 2
.
Si cierro la sesión de Julia actual, comienzo una nueva y using ctbTestModule
, ahora obtengo el comportamiento deseado, es decir, f1(1)
devuelve 3
. Pero obviamente quiero hacer esto sin reiniciar Julia.
Entonces, ¿qué estoy haciendo mal?
Otros detalles: Julia v0.2 en Ubuntu 14.04.
En julia v0.6.0 parece que usar workspace () ya no es necesario: simplemente puedo volver a cargar (MyModule) en una sesión REPL activa, y funciona como se esperaba (los cambios realizados en el archivo fuente que contiene MyModule se reflejan en el activo REPL sesión).
Esto se aplica a los módulos que se han incluido en el alcance por importación o uso
En mi humilde opinión, la mejor manera es usar la import
desde el principio en lugar de using
para el problema informado.
Considera el módulo:
module ModuleX1
export produce_text
produce_text() = begin
println("v1.0")
end
println("v1.0 loaded")
end
Luego en REPL:
julia> import ModuleX1
v1.0 loaded
julia> ModuleX1.produce_text()
v1.0
Actualice el código del módulo y guárdelo:
module ModuleX1
export produce_text
produce_text() = begin
println("v2.0")
end
println("v2.0 loaded")
end
A continuación, en REPL:
julia> reload("ModuleX1")
Warning: replacing module ModuleX1
v2.0 loaded
julia> ModuleX1.produce_text()
v2.0
Ventajas de usar import
sobre using
:
- evitando la ambigüedad en las llamadas a funciones ( ¿A qué llamar: ModuleX1.produce_text () o produce_text () después de volver a cargar? )
- no tiene que llamar al
workspace()
para deshacerse de la ambigüedad
Desventajas del uso de import
sobre el using
:
- se necesita un nombre completo en cada llamada para cada nombre exportado
Editado: descartó "acceso total al módulo, incluso a los nombres no exportados" de "Desventajas ..." según la conversación a continuación.
La base de este problema es la confluencia de volver a cargar un módulo, pero no poder redefinir una cosa en el módulo Principal ( here ) - al menos hasta que el espacio de trabajo de la nueva función () esté disponible el 13 de julio 2014. Las versiones recientes del 0.3 prelanzamiento deberían tenerlo.
Antes del espacio de trabajo ()
Considere el siguiente módulo simplista
module TstMod
export f
function f()
return 1
end
end
Entonces úsalo ...
julia> using TstMod
julia> f()
1
Si la función f () se cambia para devolver 2 y el módulo se vuelve a cargar, f se actualiza de hecho. Pero no redefinido en el módulo Principal .
julia> reload("TstMod")
Warning: replacing module TstMod
julia> TstMod.f()
2
julia> f()
1
Las siguientes advertencias aclaran el problema
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
Usar el espacio de trabajo ()
Sin embargo, el espacio de trabajo de la nueva función () borra la preparación principal para volver a cargar TstMod.
julia> workspace()
julia> reload("TstMod")
julia> using TstMod
julia> f()
2
Además, el Main anterior se almacena como LastMain
julia> whos()
Base Module
Core Module
LastMain Module
Main Module
TstMod Module
ans Nothing
julia> LastMain.f()
1
Utilice el paquete Revise
, por ejemplo
Pkg.add("Revise") # do this only once
include("src/my_module.jl")
using Revise
import my_module
Es posible que deba comenzar esto en una nueva sesión REPL. Observe el uso de import
lugar de using
, porque using
no redefine la función en el módulo Main
(como explican @Maciek Leks y @waTeim).
Otras soluciones : Dos ventajas de Revise.jl
comparación con el workspace()
de workspace()
son que (1) es mucho más rápido y (2) es a prueba de futuro, ya que workspace()
quedó obsoleto en 0.7, como se discutió en este problema de GitHub :
julia> VERSION
v"0.7.0-DEV.3089"
julia> workspace()
ERROR: UndefVarError: workspace not defined
y un colaborador de GitHub recomendó Revise.jl
:
¿Deberíamos agregar algún mensaje como "el espacio de trabajo está en desuso, eche un vistazo a Revise.jl"?
Incluso en Julia 0.6.3, las tres soluciones anteriores de workspace()
, import
y reload
fallan cuando un módulo llama a otros módulos, como DataFrames
. Con los tres métodos, recibí el mismo error cuando llamé a ese módulo por segunda vez en el mismo REPL:
ERROR: LoadError: MethodError: all(::DataFrames.##58#59, ::Array{Any,1}) is ambiguous. Candidates: ...
También recibí muchos mensajes de advertencia como:
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.
Reiniciar la sesión de Julia funcionó, pero fue engorroso. Encontré este problema en el paquete Reexport , con un mensaje de error similar:
MethodError: all(::Reexport.##2#6, ::Array{Any,1}) is ambiguous.
y siguió la sugerencia de un colaborador:
¿Esto sucede sin usar workspace ()? Esa función es notoria por interactuar mal con los paquetes, que es en parte por qué se desaprobó en 0.7.