且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何确定 julia 脚本是作为模块包含还是作为脚本运行?

更新时间:2023-12-04 22:46:46

tl;dr 版本:

if !isdefined(:__init__) || Base.function_module(__init__) != MyModule
  main()
end

说明:

似乎有些混乱.Python 和 Julia 在模块"方面的工作方式非常不同(尽管两者使用相同的术语,但原则上它们是不同的).

There seems to be some confusion. Python and Julia work very differently in terms of their "modules" (even though the two use the same term, in principle they are different).

在 python 中,源文件是模块或脚本,具体取决于您选择加载"/运行"它的方式:存在样板文件以检测运行源代码的环境,通过查询执行时嵌入模块的__name__.例如.如果您有一个名为 mymodule.py 的文件,您可以正常导入它,然后在模块定义中,变量 __name__ 会自动设置为值 mymodule代码>;但是,如果您将其作为独立脚本运行(实际上是将代码转储"到主"模块中),则 __name__ 变量是全局范围的变量,即 __main__.这种差异使您能够检测 如何 python 文件是如何运行的,因此您可以在每种情况下稍有不同,而这正是样板文件所做的.

In python, a source file is either a module or a script, depending on how you chose to "load" / "run" it: the boilerplate exists to detect the environment in which the source code was run, by querying the __name__ of the embedding module at the time of execution. E.g. if you have a file called mymodule.py, it you import it normally, then within the module definition the variable __name__ automatically gets set to the value mymodule; but if you ran it as a standalone script (effectively "dumping" the code into the "main" module), the __name__ variable is that of the global scope, namely __main__. This difference gives you the ability to detect how a python file was ran, so you could act slightly differently in each case, and this is exactly what the boilerplate does.

然而,在 julia 中,模块被明确定义为代码.运行包含 module 声明的文件将加载该模块,无论您是使用 using 还是 include;但是在前一种情况下,如果模块已经在工作区中,则不会重新加载它,而在后一种情况下,就好像您重新定义"了它一样.

In julia, however, a module is defined explicitly as code. Running a file that contains a module declaration will load that module regardless of whether you did using or include; however in the former case, the module will not be reloaded if it's already on the workspace, whereas in the latter case it's as if you "redefined" it.

模块可以通过特殊的 __init__() 函数获得初始化代码,该函数的作用是仅在模块第一次加载时运行(例如,通过 using 语句导入时).所以你可以做的一件事是有一个独立的脚本,你可以直接 include 作为一个独立的脚本运行,或者 include 它在 的范围内模块定义,并让它检测模块特定变量的存在,使其在每种情况下表现不同.但它仍然必须是一个独立的文件,与主模块定义分开.

Modules can have initialisation code via the special __init__() function, whose job is to only run the first time a module is loaded (e.g. when imported via a using statement). So one thing you could do is have a standalone script, which you could either include directly to run as a standalone script, or include it within the scope of a module definition, and have it detect the presence of module-specific variables such that it behaves differently in each case. But it would still have to be a standalone file, separate from the main module definition.

如果你想让模块做一些独立脚本不应该做的事情,这很容易:你只需要这样的东西:

If you want the module to do stuff, that the standalone script shouldn't, this is easy: you just have something like this:

module MyModule
  __init__() = # do module specific initialisation stuff here
  include("MyModule_Implementation.jl")
end

如果你想要相反的情况,你需要一种方法来检测你是否在模块内运行.你可以这样做,例如通过检测属于该特定模块的合适 __init__() 函数的存在.例如:

If you want the reverse situation, you need a way to detect whether you're running inside the module or not. You could do this, e.g. by detecting the presence of a suitable __init__() function, belonging to that particular module. For example:

### in file "MyModule.jl"
module MyModule
  export fun1, fun2;
  __init__() = print("Initialising module ...");
  include("MyModuleImplementation.jl");
end

### in file "MyModuleImplementation.jl"
fun1(a,b) = a + b;
fun2(a,b) = a * b;

main() = print("Demo of fun1 and fun2.     
" *
               "  fun1(1,2) = $(fun1(1,2)) 
" *
               "  fun2(1,2) = $(fun2(1,2)) 
");

if !isdefined(:__init__) || Base.function_module(__init__) != MyModule
  main()
end

如果将 MyModule 作为模块加载,则 MyModuleImplementation.jl 中的 main 函数将不会运行.

If MyModule is loaded as a module, the main function in MyModuleImplementation.jl will not run.

如果您将 MyModuleImplementation.jl 作为独立脚本运行,则 main 函数将运行.

If you run MyModuleImplementation.jl as a standalone script, the main function will run.

所以这是一种接近你想要的效果的方法;但这与将模块定义文件作为模块或独立脚本运行是非常不同的;我认为您不能简单地从代码中剥离" module 指令并在 julia 中以这种方式运行模块的内容".

So this is a way to achieve something close to the effect you want; but it's very different to saying running a module-defining file as either a module or a standalone script; I don't think you can simply "strip" the module instruction from the code and run the module's "contents" in such a manner in julia.